Merge changes from topic "fake-vm-without-mockito" into main

* changes:
  Remove the dependency on Mockito to create QS actions fakes (1/2)
  Remove the dependency on Mockito to create PeopleSpace fakes (1/2)
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 95b6155..433cd50 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -21,6 +21,7 @@
     ":android.os.vibrator.flags-aconfig-java{.generated_srcjars}",
     ":android.security.flags-aconfig-java{.generated_srcjars}",
     ":android.view.flags-aconfig-java{.generated_srcjars}",
+    ":android.view.accessibility.flags-aconfig-java{.generated_srcjars}",
     ":camera_platform_flags_core_java_lib{.generated_srcjars}",
     ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
     ":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}",
@@ -36,10 +37,13 @@
     ":android.permission.flags-aconfig-java{.generated_srcjars}",
     ":hwui_flags_java_lib{.generated_srcjars}",
     ":display_flags_lib{.generated_srcjars}",
+    ":com.android.internal.foldables.flags-aconfig-java{.generated_srcjars}",
     ":android.multiuser.flags-aconfig-java{.generated_srcjars}",
     ":android.app.flags-aconfig-java{.generated_srcjars}",
     ":android.credentials.flags-aconfig-java{.generated_srcjars}",
     ":android.view.contentprotection.flags-aconfig-java{.generated_srcjars}",
+    ":android.service.voice.flags-aconfig-java{.generated_srcjars}",
+    ":android.service.autofill.flags-aconfig-java{.generated_srcjars}",
 ]
 
 filegroup {
@@ -240,6 +244,29 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+cc_aconfig_library {
+    name: "aconfig_view_flags_c_lib",
+    aconfig_declarations: "android.view.flags-aconfig",
+}
+
+// View.accessibility
+aconfig_declarations {
+    name: "android.view.accessibility.flags-aconfig",
+    package: "android.view.accessibility",
+    srcs: ["core/java/android/view/accessibility/flags/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.view.accessibility.flags-aconfig-java",
+    aconfig_declarations: "android.view.accessibility.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+cc_aconfig_library {
+    name: "aconfig_view_accessibility_flags_c_lib",
+    aconfig_declarations: "android.view.accessibility.flags-aconfig",
+}
+
 // Widget
 aconfig_declarations {
     name: "android.widget.flags-aconfig",
@@ -319,6 +346,12 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+java_aconfig_library {
+    name: "com.android.internal.foldables.flags-aconfig-java",
+    aconfig_declarations: "fold_lock_setting_flags",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Multi user
 aconfig_declarations {
     name: "android.multiuser.flags-aconfig",
@@ -383,3 +416,32 @@
     aconfig_declarations: "android.view.contentprotection.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// Voice
+aconfig_declarations {
+    name: "android.service.voice.flags-aconfig",
+    package: "android.service.voice.flags",
+    srcs: ["core/java/android/service/voice/flags/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.service.voice.flags-aconfig-java",
+    aconfig_declarations: "android.service.voice.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// Autofill
+aconfig_declarations {
+    name: "android.service.autofill.flags-aconfig",
+    package: "android.service.autofill",
+    srcs: [
+        "services/autofill/bugfixes.aconfig",
+        "services/autofill/features.aconfig"
+    ],
+}
+
+java_aconfig_library {
+    name: "android.service.autofill.flags-aconfig-java",
+    aconfig_declarations: "android.service.autofill.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Android.bp b/Android.bp
index b1b332a..a507465a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,6 +64,7 @@
     srcs: [
         // Java/AIDL sources under frameworks/base
         ":framework-annotations",
+        ":ravenwood-annotations",
         ":framework-blobstore-sources",
         ":framework-core-sources",
         ":framework-drm-sources",
@@ -284,6 +285,7 @@
         enforce_permissions_exceptions: [
             // Do not add entries to this list.
             ":framework-annotations",
+            ":ravenwood-annotations",
             ":framework-blobstore-sources",
             ":framework-core-sources",
             ":framework-drm-sources",
@@ -409,7 +411,6 @@
         "audiopolicy-aidl-java",
         "sounddose-aidl-java",
         "modules-utils-expresslog",
-        "hoststubgen-annotations",
     ],
 }
 
@@ -838,4 +839,5 @@
     "AconfigFlags.bp",
     "ProtoLibraries.bp",
     "TestProtoLibraries.bp",
+    "Ravenwood.bp",
 ]
diff --git a/Android.mk b/Android.mk
index d9e202c..e2c1ed8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -69,9 +69,6 @@
 .PHONY: framework-doc-stubs
 framework-doc-stubs: $(SDK_METADATA)
 
-# Run this for checkbuild
-checkbuild: doc-comment-check-docs
-
 # Include subdirectory makefiles
 # ============================================================
 
diff --git a/OWNERS b/OWNERS
index 4e5c7d8..023bdef 100644
--- a/OWNERS
+++ b/OWNERS
@@ -34,3 +34,6 @@
 
 per-file ZYGOTE_OWNERS = file:/ZYGOTE_OWNERS
 per-file SQLITE_OWNERS = file:/SQLITE_OWNERS
+
+per-file *ravenwood* = file:ravenwood/OWNERS
+per-file *Ravenwood* = file:ravenwood/OWNERS
diff --git a/Ravenwood.bp b/Ravenwood.bp
new file mode 100644
index 0000000..9218cc9
--- /dev/null
+++ b/Ravenwood.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2023 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.
+
+// We need this "trampoline" rule to force soong to give a host-side jar to
+// framework-minus-apex.ravenwood. Otherwise, soong would mix up the arch (?) and we'd get
+// a dex jar.
+java_library {
+    name: "framework-minus-apex-for-hoststubgen",
+    installable: false, // host only jar.
+    static_libs: [
+        "framework-minus-apex",
+    ],
+    sdk_version: "core_platform",
+    visibility: ["//visibility:private"],
+}
+
+// Generate the stub/impl from framework-all, with hidden APIs.
+java_genrule_host {
+    name: "framework-minus-apex.ravenwood-base",
+    tools: ["hoststubgen"],
+    cmd: "$(location hoststubgen) " +
+        "@$(location :ravenwood-standard-options) " +
+
+        "--out-stub-jar $(location ravenwood_stub.jar) " +
+        "--out-impl-jar $(location ravenwood.jar) " +
+
+        "--gen-keep-all-file $(location hoststubgen_keep_all.txt) " +
+        "--gen-input-dump-file $(location hoststubgen_dump.txt) " +
+
+        "--in-jar $(location :framework-minus-apex-for-hoststubgen) " +
+        "--policy-override-file $(location framework-minus-apex-ravenwood-policies.txt) ",
+    srcs: [
+        ":framework-minus-apex-for-hoststubgen",
+        "framework-minus-apex-ravenwood-policies.txt",
+        ":ravenwood-standard-options",
+    ],
+    out: [
+        "ravenwood.jar",
+        "ravenwood_stub.jar", // It's not used. TODO: Update hoststubgen to make it optional.
+
+        // Following files are created just as FYI.
+        "hoststubgen_keep_all.txt",
+        "hoststubgen_dump.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Extract the impl jar from "framework-minus-apex.ravenwood-base" for subsequent build rules.
+java_genrule_host {
+    name: "framework-minus-apex.ravenwood",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-minus-apex.ravenwood-base{ravenwood.jar}",
+    ],
+    out: [
+        "framework-minus-apex.ravenwood.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index a4a0b4b..887f7fe 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -13,6 +13,10 @@
     name: "service-jobscheduler",
     installable: true,
 
+    defaults: [
+        "service-jobscheduler-aconfig-libraries",
+    ],
+
     srcs: [
         "java/**/*.java",
         ":framework-jobscheduler-shared-srcs",
diff --git a/apex/jobscheduler/service/aconfig/Android.bp b/apex/jobscheduler/service/aconfig/Android.bp
new file mode 100644
index 0000000..24ecd3d
--- /dev/null
+++ b/apex/jobscheduler/service/aconfig/Android.bp
@@ -0,0 +1,29 @@
+// JobScheduler
+aconfig_declarations {
+    name: "service-job.flags-aconfig",
+    package: "com.android.server.job",
+    srcs: [
+        "job.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "service-jobscheduler-job.flags-aconfig-java",
+    aconfig_declarations: "service-job.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+    visibility: ["//frameworks/base:__subpackages__"],
+}
+
+service_jobscheduler_aconfig_srcjars = [
+    ":service-jobscheduler-job.flags-aconfig-java{.generated_srcjars}",
+]
+
+// Aconfig declarations and libraries for the core framework
+java_defaults {
+    name: "service-jobscheduler-aconfig-libraries",
+    // Add java_aconfig_libraries to here to add them to the core framework
+    srcs: service_jobscheduler_aconfig_srcjars,
+    // Add aconfig-annotations-lib as a dependency for the optimization
+    libs: ["aconfig-annotations-lib"],
+    visibility: ["//frameworks/base:__subpackages__"],
+}
diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig
new file mode 100644
index 0000000..4e3cb7d
--- /dev/null
+++ b/apex/jobscheduler/service/aconfig/job.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.job"
+
+flag {
+    name: "relax_prefetch_connectivity_constraint_only_on_charger"
+    namespace: "backstagepower"
+    description: "Only relax a prefetch job's connectivity constraint when the device is charging"
+    bug: "299329948"
+}
\ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index f252a0b..158d914 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -1030,6 +1030,12 @@
                 "light_idle_to_initial_flex";
         private static final String KEY_LIGHT_IDLE_TIMEOUT_MAX_FLEX = "light_max_idle_to_flex";
         private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
+        private static final String KEY_LIGHT_IDLE_INCREASE_LINEARLY =
+                "light_idle_increase_linearly";
+        private static final String KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS =
+                "light_idle_linear_increase_factor_ms";
+        private static final String KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS =
+                "light_idle_flex_linear_increase_factor_ms";
         private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
         private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
                 "light_idle_maintenance_min_budget";
@@ -1079,6 +1085,10 @@
         private long mDefaultLightIdleTimeoutMaxFlex =
                 !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
         private float mDefaultLightIdleFactor = 2f;
+        private boolean mDefaultLightIdleIncreaseLinearly;
+        private long mDefaultLightIdleLinearIncreaseFactorMs = mDefaultLightIdleTimeout;
+        private long mDefaultLightIdleFlexLinearIncreaseFactorMs =
+                mDefaultLightIdleTimeoutInitialFlex;
         private long mDefaultLightMaxIdleTimeout =
                 !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
         private long mDefaultLightIdleMaintenanceMinBudget =
@@ -1174,6 +1184,37 @@
         public float LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
 
         /**
+         * Whether to increase the light idle mode time linearly or exponentially.
+         * If true, will increase linearly
+         * (i.e. {@link #LIGHT_IDLE_TIMEOUT} + x * {@link #LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS}).
+         * If false, will increase by exponentially
+         * (i.e. {@link #LIGHT_IDLE_TIMEOUT} * ({@link #LIGHT_IDLE_FACTOR} ^ x)).
+         * This will also impact how the light idle flex value
+         * ({@link #LIGHT_IDLE_TIMEOUT_INITIAL_FLEX}) is increased (using
+         * {@link #LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS} for the linear increase)..
+         *
+         * @see #KEY_LIGHT_IDLE_INCREASE_LINEARLY
+         */
+        public boolean LIGHT_IDLE_INCREASE_LINEARLY = mDefaultLightIdleIncreaseLinearly;
+
+        /**
+         * Amount of time to increase the light idle time by, if increasing it linearly.
+         *
+         * @see #KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS
+         * @see #LIGHT_IDLE_INCREASE_LINEARLY
+         */
+        public long LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleLinearIncreaseFactorMs;
+
+        /**
+         * Amount of time to increase the light idle flex time by, if increasing it linearly.
+         *
+         * @see #KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS
+         * @see #LIGHT_IDLE_INCREASE_LINEARLY
+         */
+        public long LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS =
+                mDefaultLightIdleFlexLinearIncreaseFactorMs;
+
+        /**
          * This is the maximum time we will stay in light idle mode.
          *
          * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
@@ -1409,6 +1450,16 @@
                     mDefaultLightIdleTimeoutMaxFlex);
             mDefaultLightIdleFactor = res.getFloat(
                     com.android.internal.R.integer.device_idle_light_idle_factor);
+            mDefaultLightIdleIncreaseLinearly = res.getBoolean(
+                    com.android.internal.R.bool.device_idle_light_idle_increase_linearly);
+            mDefaultLightIdleLinearIncreaseFactorMs = getTimeout(res.getInteger(
+                    com.android.internal.R.integer
+                            .device_idle_light_idle_linear_increase_factor_ms),
+                    mDefaultLightIdleLinearIncreaseFactorMs);
+            mDefaultLightIdleFlexLinearIncreaseFactorMs = getTimeout(res.getInteger(
+                    com.android.internal.R.integer
+                            .device_idle_light_idle_flex_linear_increase_factor_ms),
+                    mDefaultLightIdleFlexLinearIncreaseFactorMs);
             mDefaultLightMaxIdleTimeout = getTimeout(
                     res.getInteger(com.android.internal.R.integer.device_idle_light_max_idle_to_ms),
                     mDefaultLightMaxIdleTimeout);
@@ -1487,6 +1538,9 @@
             LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = mDefaultLightIdleTimeoutInitialFlex;
             LIGHT_IDLE_TIMEOUT_MAX_FLEX = mDefaultLightIdleTimeoutMaxFlex;
             LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
+            LIGHT_IDLE_INCREASE_LINEARLY = mDefaultLightIdleIncreaseLinearly;
+            LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleLinearIncreaseFactorMs;
+            LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleFlexLinearIncreaseFactorMs;
             LIGHT_MAX_IDLE_TIMEOUT = mDefaultLightMaxIdleTimeout;
             LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mDefaultLightIdleMaintenanceMinBudget;
             LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mDefaultLightIdleMaintenanceMaxBudget;
@@ -1556,6 +1610,21 @@
                             LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
                                     KEY_LIGHT_IDLE_FACTOR, mDefaultLightIdleFactor));
                             break;
+                        case KEY_LIGHT_IDLE_INCREASE_LINEARLY:
+                            LIGHT_IDLE_INCREASE_LINEARLY = properties.getBoolean(
+                                    KEY_LIGHT_IDLE_INCREASE_LINEARLY,
+                                    mDefaultLightIdleIncreaseLinearly);
+                            break;
+                        case KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS:
+                            LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = properties.getLong(
+                                    KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS,
+                                    mDefaultLightIdleLinearIncreaseFactorMs);
+                            break;
+                        case KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS:
+                            LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS = properties.getLong(
+                                    KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS,
+                                    mDefaultLightIdleFlexLinearIncreaseFactorMs);
+                            break;
                         case KEY_LIGHT_MAX_IDLE_TIMEOUT:
                             LIGHT_MAX_IDLE_TIMEOUT = properties.getLong(
                                     KEY_LIGHT_MAX_IDLE_TIMEOUT, mDefaultLightMaxIdleTimeout);
@@ -1716,6 +1785,20 @@
             pw.print(LIGHT_IDLE_FACTOR);
             pw.println();
 
+            pw.print("    "); pw.print(KEY_LIGHT_IDLE_INCREASE_LINEARLY); pw.print("=");
+            pw.print(LIGHT_IDLE_INCREASE_LINEARLY);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS);
+            pw.print("=");
+            pw.print(LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS);
+            pw.print("=");
+            pw.print(LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS);
+            pw.println();
+
             pw.print("    "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT); pw.print("=");
             TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT, pw);
             pw.println();
@@ -3694,10 +3777,18 @@
                 }
                 mMaintenanceStartTime = 0;
                 scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex, true);
-                mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
-                        (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
-                mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX,
-                        (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
+                if (!mConstants.LIGHT_IDLE_INCREASE_LINEARLY) {
+                    mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
+                            (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
+                    mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX,
+                            (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
+                } else {
+                    mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
+                            mNextLightIdleDelay + mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS);
+                    mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX,
+                            mNextLightIdleDelayFlex
+                                    + mConstants.LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS);
+                }
                 moveToLightStateLocked(LIGHT_STATE_IDLE, reason);
                 addEvent(EVENT_LIGHT_IDLE, null);
                 mGoingIdleWakeLock.acquire();
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 43d2ae9..f47766e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -1335,13 +1335,13 @@
     private void handleOpTimeoutLocked() {
         switch (mVerb) {
             case VERB_BINDING:
-                onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true,
+                // The system may have been too busy. Don't drop the job or trigger an ANR.
+                onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ true,
                         /* texCounterMetricId */
                         "job_scheduler.value_cntr_w_uid_slow_app_response_binding",
                         /* debugReason */ "timed out while binding",
                         /* anrMessage */ "Timed out while trying to bind",
-                        CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES,
-                            mRunningJob.getUid()));
+                        /* triggerAnr */ false);
                 break;
             case VERB_STARTING:
                 // Client unresponsive - wedged or failed to respond in time. We don't really
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 6d938de..45f15db 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -22,6 +22,8 @@
 
 import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.Flags.FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER;
+import static com.android.server.job.Flags.relaxPrefetchConnectivityConstraintOnlyOnCharger;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -929,6 +931,11 @@
             // Need to at least know the estimated download bytes for a prefetch job.
             return false;
         }
+        if (relaxPrefetchConnectivityConstraintOnlyOnCharger()) {
+            if (!mService.isBatteryCharging()) {
+                return false;
+            }
+        }
 
         // See if we match after relaxing any unmetered request
         final NetworkCapabilities.Builder builder =
@@ -1735,6 +1742,14 @@
             Predicate<JobStatus> predicate) {
         final long nowElapsed = sElapsedRealtimeClock.millis();
 
+        pw.println("Aconfig flags:");
+        pw.increaseIndent();
+        pw.print(FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER,
+                relaxPrefetchConnectivityConstraintOnlyOnCharger());
+        pw.println();
+        pw.decreaseIndent();
+        pw.println();
+
         if (mRequestedWhitelistJobs.size() > 0) {
             pw.print("Requested standby exceptions:");
             for (int i = 0; i < mRequestedWhitelistJobs.size(); i++) {
diff --git a/api/Android.bp b/api/Android.bp
index f017a47..222275f 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -62,15 +62,6 @@
 metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
 metalava_cmd += " --quiet "
 
-genrule {
-    name: "current-api-xml",
-    tools: ["metalava"],
-    srcs: [":frameworks-base-api-current.txt"],
-    out: ["current.api"],
-    cmd: metalava_cmd + "signature-to-jdiff $(in) $(out)",
-    visibility: ["//visibility:public"],
-}
-
 combined_apis {
     name: "frameworks-base-api",
     bootclasspath: [
@@ -91,7 +82,6 @@
         "framework-media",
         "framework-mediaprovider",
         "framework-ondevicepersonalization",
-        "framework-pdf",
         "framework-permission",
         "framework-permission-s",
         "framework-scheduling",
diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp
index fbcaa52..30b4423 100644
--- a/api/ApiDocs.bp
+++ b/api/ApiDocs.bp
@@ -20,41 +20,6 @@
 // The API doc generation is done by the various droiddoc modules each of which
 // is for different format.
 
-/////////////////////////////////////////////////////////////////////
-// stub source files are generated using metalava
-/////////////////////////////////////////////////////////////////////
-
-framework_docs_only_libs = [
-    "voip-common",
-    "android.test.mock",
-    "android-support-annotations",
-    "android-support-compat",
-    "android-support-core-ui",
-    "android-support-core-utils",
-    "android-support-design",
-    "android-support-dynamic-animation",
-    "android-support-exifinterface",
-    "android-support-fragment",
-    "android-support-media-compat",
-    "android-support-percent",
-    "android-support-transition",
-    "android-support-v7-cardview",
-    "android-support-v7-gridlayout",
-    "android-support-v7-mediarouter",
-    "android-support-v7-palette",
-    "android-support-v7-preference",
-    "android-support-v13",
-    "android-support-v14-preference",
-    "android-support-v17-leanback",
-    "android-support-vectordrawable",
-    "android-support-animatedvectordrawable",
-    "android-support-v7-appcompat",
-    "android-support-v7-recyclerview",
-    "android-support-v8-renderscript",
-    "android-support-multidex",
-    "android-support-multidex-instrumentation",
-]
-
 // These defaults enable doc-stub generation, api lint database generation and sdk value generation.
 stubs_defaults {
     name: "android-non-updatable-doc-stubs-defaults",
@@ -65,7 +30,6 @@
         ":android-test-mock-sources",
         ":android-test-runner-sources",
     ],
-    libs: framework_docs_only_libs,
     create_doc_stubs: true,
     write_sdk_values: true,
 }
@@ -195,7 +159,9 @@
 
 doc_defaults {
     name: "framework-docs-default",
-    libs: framework_docs_only_libs + [
+    sdk_version: "none",
+    system_modules: "none",
+    libs: [
         "stub-annotations",
         "unsupportedappusage",
     ],
@@ -209,6 +175,7 @@
     custom_template: "droiddoc-templates-sdk",
     resourcesdir: "docs/html/reference/images/",
     resourcesoutdir: "reference/android/images/",
+    lint_baseline: "javadoc-lint-baseline",
     hdf: [
         "dac true",
         "sdk.codename O",
@@ -233,20 +200,6 @@
     },
 }
 
-doc_defaults {
-    name: "framework-dokka-docs-default",
-}
-
-droiddoc {
-    name: "doc-comment-check-docs",
-    defaults: ["framework-docs-default"],
-    srcs: [
-        ":framework-doc-stubs",
-    ],
-    args: framework_docs_only_args + " -referenceonly -parsecomments",
-    installable: false,
-}
-
 droiddoc {
     name: "offline-sdk-docs",
     defaults: ["framework-docs-default"],
@@ -300,70 +253,6 @@
 }
 
 droiddoc {
-    name: "online-sdk-docs",
-    defaults: ["framework-docs-default"],
-    srcs: [
-        ":framework-doc-stubs",
-    ],
-    hdf: [
-        "android.whichdoc online",
-        "android.hasSamples true",
-    ],
-    proofread_file: "online-sdk-docs-proofread.txt",
-    args: framework_docs_only_args +
-        " -toroot / -samplegroup Admin " +
-        " -samplegroup Background " +
-        " -samplegroup Connectivity " +
-        " -samplegroup Content " +
-        " -samplegroup Input " +
-        " -samplegroup Media " +
-        " -samplegroup Notification " +
-        " -samplegroup RenderScript " +
-        " -samplegroup Security " +
-        " -samplegroup Sensors " +
-        " -samplegroup System " +
-        " -samplegroup Testing " +
-        " -samplegroup UI " +
-        " -samplegroup Views " +
-        " -samplegroup Wearable -samplesdir development/samples/browseable ",
-}
-
-droiddoc {
-    name: "online-system-api-sdk-docs",
-    defaults: ["framework-docs-default"],
-    srcs: [
-        ":framework-doc-system-stubs",
-    ],
-    hdf: [
-        "android.whichdoc online",
-        "android.hasSamples true",
-    ],
-    proofread_file: "online-system-api-sdk-docs-proofread.txt",
-    args: framework_docs_only_args +
-        " -referenceonly " +
-        " -title \"Android SDK - Including system APIs.\" " +
-        " -hide 101 " +
-        " -hide 104 " +
-        " -hide 108 " +
-        " -toroot / -samplegroup Admin " +
-        " -samplegroup Background " +
-        " -samplegroup Connectivity " +
-        " -samplegroup Content " +
-        " -samplegroup Input " +
-        " -samplegroup Media " +
-        " -samplegroup Notification " +
-        " -samplegroup RenderScript " +
-        " -samplegroup Security " +
-        " -samplegroup Sensors " +
-        " -samplegroup System " +
-        " -samplegroup Testing " +
-        " -samplegroup UI " +
-        " -samplegroup Views " +
-        " -samplegroup Wearable -samplesdir development/samples/browseable ",
-    installable: false,
-}
-
-droiddoc {
     name: "ds-docs-java",
     defaults: ["framework-docs-default"],
     srcs: [
@@ -394,7 +283,6 @@
 
 droiddoc {
     name: "ds-docs-kt",
-    defaults: ["framework-dokka-docs-default"],
     srcs: [
         ":framework-doc-stubs",
     ],
@@ -473,44 +361,3 @@
         " -atLinksNavtree " +
         " -navtreeonly ",
 }
-
-droiddoc {
-    name: "online-sdk-dev-docs",
-    defaults: ["framework-docs-default"],
-    srcs: [
-        ":framework-doc-stubs",
-    ],
-    hdf: [
-        "android.whichdoc online",
-        "android.hasSamples true",
-    ],
-    proofread_file: "online-sdk-dev-docs-proofread.txt",
-    args: framework_docs_only_args +
-        " -toroot / -samplegroup Admin " +
-        " -samplegroup Background " +
-        " -samplegroup Connectivity " +
-        " -samplegroup Content " +
-        " -samplegroup Input " +
-        " -samplegroup Media " +
-        " -samplegroup Notification " +
-        " -samplegroup RenderScript " +
-        " -samplegroup Security " +
-        " -samplegroup Sensors " +
-        " -samplegroup System " +
-        " -samplegroup Testing " +
-        " -samplegroup UI " +
-        " -samplegroup Views " +
-        " -samplegroup Wearable -samplesdir development/samples/browseable ",
-}
-
-droiddoc {
-    name: "hidden-docs",
-    defaults: ["framework-docs-default"],
-    srcs: [
-        ":framework-doc-stubs",
-    ],
-    proofread_file: "hidden-docs-proofread.txt",
-    args: framework_docs_only_args +
-        " -referenceonly " +
-        " -title \"Android SDK - Including hidden APIs.\"",
-}
diff --git a/api/api.go b/api/api.go
index 83804c6..8df6dab 100644
--- a/api/api.go
+++ b/api/api.go
@@ -115,6 +115,7 @@
 }
 
 type Bazel_module struct {
+	Label              *string
 	Bp2build_available *bool
 }
 type bazelProperties struct {
@@ -141,6 +142,8 @@
 	ModuleTag string
 	// public, system, module-lib or system-server
 	Scope string
+	// True if there is a bp2build definition for this module
+	Bp2buildDefined bool
 }
 
 func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) {
@@ -153,8 +156,10 @@
 	if txt.Scope != "public" {
 		filename = txt.Scope + "-" + filename
 	}
+	moduleName := ctx.ModuleName() + "-" + filename
+
 	props := genruleProps{}
-	props.Name = proptools.StringPtr(ctx.ModuleName() + "-" + filename)
+	props.Name = proptools.StringPtr(moduleName)
 	props.Tools = []string{"metalava"}
 	props.Out = []string{filename}
 	props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --out $(out)")
@@ -172,7 +177,20 @@
 		},
 	}
 	props.Visibility = []string{"//visibility:public"}
-	ctx.CreateModule(genrule.GenRuleFactory, &props, &bp2buildNotAvailable)
+	bazelProps := bazelProperties{
+		&Bazel_module{
+			Bp2build_available: proptools.BoolPtr(false),
+		},
+	}
+	if txt.Bp2buildDefined {
+		moduleDir := ctx.ModuleDir()
+		if moduleDir == android.Bp2BuildTopLevel {
+			moduleDir = ""
+		}
+		label := fmt.Sprintf("//%s:%s", moduleDir, moduleName)
+		bazelProps.Label = &label
+	}
+	ctx.CreateModule(genrule.GenRuleFactory, &props, &bazelProps)
 }
 
 func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, system_server_modules []string) {
@@ -304,38 +322,43 @@
 
 	tagSuffix := []string{".api.txt}", ".removed-api.txt}"}
 	distFilename := []string{"android.txt", "android-removed.txt"}
+	bp2BuildDefined := []bool{true, false}
 	for i, f := range []string{"current.txt", "removed.txt"} {
 		textFiles = append(textFiles, MergedTxtDefinition{
-			TxtFilename:  f,
-			DistFilename: distFilename[i],
-			BaseTxt:      ":non-updatable-" + f,
-			Modules:      bootclasspath,
-			ModuleTag:    "{.public" + tagSuffix[i],
-			Scope:        "public",
+			TxtFilename:     f,
+			DistFilename:    distFilename[i],
+			BaseTxt:         ":non-updatable-" + f,
+			Modules:         bootclasspath,
+			ModuleTag:       "{.public" + tagSuffix[i],
+			Scope:           "public",
+			Bp2buildDefined: bp2BuildDefined[i],
 		})
 		textFiles = append(textFiles, MergedTxtDefinition{
-			TxtFilename:  f,
-			DistFilename: distFilename[i],
-			BaseTxt:      ":non-updatable-system-" + f,
-			Modules:      bootclasspath,
-			ModuleTag:    "{.system" + tagSuffix[i],
-			Scope:        "system",
+			TxtFilename:     f,
+			DistFilename:    distFilename[i],
+			BaseTxt:         ":non-updatable-system-" + f,
+			Modules:         bootclasspath,
+			ModuleTag:       "{.system" + tagSuffix[i],
+			Scope:           "system",
+			Bp2buildDefined: bp2BuildDefined[i],
 		})
 		textFiles = append(textFiles, MergedTxtDefinition{
-			TxtFilename:  f,
-			DistFilename: distFilename[i],
-			BaseTxt:      ":non-updatable-module-lib-" + f,
-			Modules:      bootclasspath,
-			ModuleTag:    "{.module-lib" + tagSuffix[i],
-			Scope:        "module-lib",
+			TxtFilename:     f,
+			DistFilename:    distFilename[i],
+			BaseTxt:         ":non-updatable-module-lib-" + f,
+			Modules:         bootclasspath,
+			ModuleTag:       "{.module-lib" + tagSuffix[i],
+			Scope:           "module-lib",
+			Bp2buildDefined: bp2BuildDefined[i],
 		})
 		textFiles = append(textFiles, MergedTxtDefinition{
-			TxtFilename:  f,
-			DistFilename: distFilename[i],
-			BaseTxt:      ":non-updatable-system-server-" + f,
-			Modules:      system_server_classpath,
-			ModuleTag:    "{.system-server" + tagSuffix[i],
-			Scope:        "system-server",
+			TxtFilename:     f,
+			DistFilename:    distFilename[i],
+			BaseTxt:         ":non-updatable-system-server-" + f,
+			Modules:         system_server_classpath,
+			ModuleTag:       "{.system-server" + tagSuffix[i],
+			Scope:           "system-server",
+			Bp2buildDefined: bp2BuildDefined[i],
 		})
 	}
 	for _, txt := range textFiles {
diff --git a/api/api_test.go b/api/api_test.go
index 1f4c2af..70f2162 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -33,6 +33,8 @@
 	t.Helper()
 	runCombinedApisTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("java_defaults", java.DefaultsFactory)
+		ctx.RegisterModuleType("java_sdk_library", java.SdkLibraryFactory)
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	})
 }
 
@@ -44,6 +46,33 @@
     bootclasspath: ["bcp"],
     system_server_classpath: ["ssc"],
 }
+
+java_sdk_library {
+		name: "bcp",
+		srcs: ["a.java", "b.java"],
+		shared_library: false,
+}
+java_sdk_library {
+		name: "ssc",
+		srcs: ["a.java", "b.java"],
+		shared_library: false,
+}
+filegroup {
+    name: "non-updatable-current.txt",
+    srcs: ["current.txt"],
+}
+filegroup {
+    name: "non-updatable-system-current.txt",
+    srcs: ["system-current.txt"],
+}
+filegroup {
+    name: "non-updatable-module-lib-current.txt",
+    srcs: ["system-removed.txt"],
+}
+filegroup {
+    name: "non-updatable-system-server-current.txt",
+    srcs: ["system-lint-baseline.txt"],
+}
 `,
 		Filesystem: map[string]string{
 			"a/Android.bp": `
@@ -51,27 +80,35 @@
 				name: "android.jar_defaults",
 			}
 			`,
+			"api/current.txt":        "",
+			"api/removed.txt":        "",
+			"api/system-current.txt": "",
+			"api/system-removed.txt": "",
+			"api/test-current.txt":   "",
+			"api/test-removed.txt":   "",
 		},
+		StubbedBuildDefinitions:    []string{"bcp", "ssc", "non-updatable-current.txt", "non-updatable-system-current.txt", "non-updatable-module-lib-current.txt", "non-updatable-system-server-current.txt"},
+		ExpectedHandcraftedModules: []string{"foo-current.txt", "foo-system-current.txt", "foo-module-lib-current.txt", "foo-system-server-current.txt"},
 		ExpectedBazelTargets: []string{
 			bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-current.txt", bp2build.AttrNameToString{
 				"scope": `"public"`,
-				"base":  `":non-updatable-current.txt__BP2BUILD__MISSING__DEP"`,
-				"deps":  `[":bcp__BP2BUILD__MISSING__DEP"]`,
+				"base":  `":non-updatable-current.txt"`,
+				"deps":  `[":bcp"]`,
 			}),
 			bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-system-current.txt", bp2build.AttrNameToString{
 				"scope": `"system"`,
-				"base":  `":non-updatable-system-current.txt__BP2BUILD__MISSING__DEP"`,
-				"deps":  `[":bcp__BP2BUILD__MISSING__DEP"]`,
+				"base":  `":non-updatable-system-current.txt"`,
+				"deps":  `[":bcp"]`,
 			}),
 			bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-module-lib-current.txt", bp2build.AttrNameToString{
 				"scope": `"module-lib"`,
-				"base":  `":non-updatable-module-lib-current.txt__BP2BUILD__MISSING__DEP"`,
-				"deps":  `[":bcp__BP2BUILD__MISSING__DEP"]`,
+				"base":  `":non-updatable-module-lib-current.txt"`,
+				"deps":  `[":bcp"]`,
 			}),
 			bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-system-server-current.txt", bp2build.AttrNameToString{
 				"scope": `"system-server"`,
-				"base":  `":non-updatable-system-server-current.txt__BP2BUILD__MISSING__DEP"`,
-				"deps":  `[":ssc__BP2BUILD__MISSING__DEP"]`,
+				"base":  `":non-updatable-system-server-current.txt"`,
+				"deps":  `[":ssc"]`,
 			}),
 		},
 	})
diff --git a/api/javadoc-lint-baseline b/api/javadoc-lint-baseline
new file mode 100644
index 0000000..2cc5078
--- /dev/null
+++ b/api/javadoc-lint-baseline
@@ -0,0 +1,303 @@
+android/adservices/ondevicepersonalization/DownloadCompletedInput.java:22: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onDownloadCompleted() IsolatedWorker#onDownloadCompleted()" in android.adservices.ondevicepersonalization.DownloadCompletedInput [101]
+android/adservices/ondevicepersonalization/DownloadCompletedOutput.java:21: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onDownloadCompleted() IsolatedWorker#onDownloadCompleted()" in android.adservices.ondevicepersonalization.DownloadCompletedOutput [101]
+android/adservices/ondevicepersonalization/EventLogRecord.java:13: lint: Unresolved link/see tag "RequestRecordRecord" in android.adservices.ondevicepersonalization.EventLogRecord [101]
+android/adservices/ondevicepersonalization/EventUrlProvider.java:43: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onEvent IsolatedWorker#onEvent" in android.adservices.ondevicepersonalization.EventUrlProvider [101]
+android/adservices/ondevicepersonalization/ExecuteInput.java:22: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.ExecuteInput [101]
+android/adservices/ondevicepersonalization/ExecuteOutput.java:20: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.ExecuteOutput [101]
+android/adservices/ondevicepersonalization/ExecuteOutput.java:20: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.OnDevicePersonalizationManager#execute() OnDevicePersonalizationManager#execute()" in android.adservices.ondevicepersonalization.ExecuteOutput [101]
+android/adservices/ondevicepersonalization/ExecuteOutput.java:31: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.ExecuteOutput [101]
+android/adservices/ondevicepersonalization/ExecuteOutput.java:93: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.ExecuteOutput.Builder [101]
+android/adservices/ondevicepersonalization/IsolatedService.java:18: lint: Unresolved link/see tag "SurfaceView" in android.adservices.ondevicepersonalization.IsolatedService [101]
+android/adservices/ondevicepersonalization/IsolatedService.java:18: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.OnDevicePersonalizationManager#execute" in android.adservices.ondevicepersonalization.IsolatedService [101]
+android/adservices/ondevicepersonalization/IsolatedService.java:119: lint: Unresolved link/see tag "IsolatedCmputationCallback#onWebViewEvent()" in android.adservices.ondevicepersonalization.IsolatedService [101]
+android/adservices/ondevicepersonalization/IsolatedService.java:119: lint: Unresolved link/see tag "IsolatedCmputationCallback#onEvent()" in android.adservices.ondevicepersonalization.IsolatedService [101]
+android/adservices/ondevicepersonalization/IsolatedService.java:119: lint: Unresolved link/see tag "WebView" in android.adservices.ondevicepersonalization.IsolatedService [101]
+android/adservices/ondevicepersonalization/IsolatedWorker.java:9: lint: Unresolved link/see tag "RunTimeException" in android.adservices.ondevicepersonalization.IsolatedWorker [101]
+android/adservices/ondevicepersonalization/IsolatedWorker.java:24: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.OnDevicePersonalizationManager#execute" in android.adservices.ondevicepersonalization.IsolatedWorker [101]
+android/adservices/ondevicepersonalization/IsolatedWorker.java:57: lint: Unresolved link/see tag "#onExecute()" in android.adservices.ondevicepersonalization.IsolatedWorker [101]
+android/adservices/ondevicepersonalization/IsolatedWorker.java:74: lint: Unresolved link/see tag "#onRender()" in android.adservices.ondevicepersonalization.IsolatedWorker [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:-11: lint: Unresolved link/see tag "requestSurfacePackage" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:11: lint: Unresolved link/see tag "SurfaceView" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:11: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedService#onExecute() IsolatedService#onExecute()" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:19: lint: Unresolved link/see tag "SurfaceView" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:54: lint: Unresolved link/see tag "SurfaceView" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:54: lint: Unresolved link/see tag "SurfaceView#getHostToken()" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:54: lint: Unresolved link/see tag "execute" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:60: lint: Unresolved link/see tag "#execute()" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:60: lint: Unresolved link/see tag "SurfacePackage" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:60: lint: Unresolved link/see tag "SurfaceView" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:60: lint: Unresolved link/see tag "View" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:64: lint: Unresolved link/see tag "SurfacePackage" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:69: lint: Unresolved link/see tag "SurfacePackage" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java:70: lint: Unresolved link/see tag "SurfacePackage" in android.adservices.ondevicepersonalization.OnDevicePersonalizationManager [101]
+android/adservices/ondevicepersonalization/RenderInput.java:21: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onRender() IsolatedWorker#onRender()" in android.adservices.ondevicepersonalization.RenderInput [101]
+android/adservices/ondevicepersonalization/RenderInput.java:53: lint: Unresolved link/see tag "onExecute" in android.adservices.ondevicepersonalization.RenderInput [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:20: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.RenderOutput [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:20: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.OnDevicePersonalizationManager#requestSurfacePackage() OnDevicePersonalizationManager#requestSurfacePackage()" in android.adservices.ondevicepersonalization.RenderOutput [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:31: lint: Unresolved link/see tag "getTemplateId()" in android.adservices.ondevicepersonalization.RenderOutput [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:31: lint: Unresolved link/see tag "getTemplateParams" in android.adservices.ondevicepersonalization.RenderOutput [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:41: lint: Unresolved link/see tag "getContent()" in android.adservices.ondevicepersonalization.RenderOutput [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:52: lint: Unresolved link/see tag "getTemplateId()" in android.adservices.ondevicepersonalization.RenderOutput [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:102: lint: Unresolved link/see tag "getTemplateId()" in android.adservices.ondevicepersonalization.RenderOutput.Builder [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:102: lint: Unresolved link/see tag "getTemplateParams" in android.adservices.ondevicepersonalization.RenderOutput.Builder [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:114: lint: Unresolved link/see tag "getContent()" in android.adservices.ondevicepersonalization.RenderOutput.Builder [101]
+android/adservices/ondevicepersonalization/RenderOutput.java:127: lint: Unresolved link/see tag "getTemplateId()" in android.adservices.ondevicepersonalization.RenderOutput.Builder [101]
+android/adservices/ondevicepersonalization/RenderingConfig.java:20: lint: Unresolved link/see tag "View" in android.adservices.ondevicepersonalization.RenderingConfig [101]
+android/adservices/ondevicepersonalization/RenderingConfig.java:20: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.RenderingConfig [101]
+android/adservices/ondevicepersonalization/RenderingConfig.java:20: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onRender() IsolatedWorker#onRender()" in android.adservices.ondevicepersonalization.RenderingConfig [101]
+android/adservices/ondevicepersonalization/RenderingConfig.java:33: lint: Unresolved link/see tag "IsolatedSurface#getRemoteData" in android.adservices.ondevicepersonalization.RenderingConfig [101]
+android/adservices/ondevicepersonalization/RenderingConfig.java:85: lint: Unresolved link/see tag "IsolatedSurface#getRemoteData" in android.adservices.ondevicepersonalization.RenderingConfig.Builder [101]
+android/adservices/ondevicepersonalization/RequestLogRecord.java:19: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.RequestLogRecord [101]
+android/adservices/ondevicepersonalization/SurfacePackageToken.java:20: lint: Unresolved link/see tag "SurfaceView" in android.adservices.ondevicepersonalization.SurfacePackageToken [101]
+android/adservices/ondevicepersonalization/WebViewEventInput.java:21: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onWebViewEvent() IsolatedWorker#onWebViewEvent()" in android.adservices.ondevicepersonalization.WebViewEventInput [101]
+android/adservices/ondevicepersonalization/WebViewEventInput.java:30: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.WebViewEventInput [101]
+android/adservices/ondevicepersonalization/WebViewEventInput.java:41: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.EventUrlProvider#createEventTrackingUrlWithResponse() EventUrlProvider#createEventTrackingUrlWithResponse()" in android.adservices.ondevicepersonalization.WebViewEventInput [101]
+android/adservices/ondevicepersonalization/WebViewEventOutput.java:21: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onWebViewEvent() IsolatedWorker#onWebViewEvent()" in android.adservices.ondevicepersonalization.WebViewEventOutput [101]
+android/app/ActivityOptions.java:366: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101]
+android/app/ActivityOptions.java:370: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101]
+android/app/ActivityOptions.java:384: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101]
+android/app/ApplicationStartInfo.java:96: lint: Unresolved link/see tag "#START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE" in android.app.ApplicationStartInfo [101]
+android/app/BroadcastOptions.java:132: lint: Unresolved link/see tag "#setDeliveryGroupMatchingFilter(android.content.IntentFilter)" in android.app.BroadcastOptions [101]
+android/app/GrammaticalInflectionManager.java:60: lint: Unresolved link/see tag "android.os.Environment#getDataSystemCeDirectory(int)" in android.app.GrammaticalInflectionManager [101]
+android/app/Notification.java:509: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.app.Notification [101]
+android/app/Notification.java:650: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.app.Notification [101]
+android/app/Notification.java:1866: lint: Unresolved link/see tag "/*missing*/" in android.app.Notification.Action [101]
+android/app/Notification.java:4796: lint: Unresolved link/see tag "android.content.pm.ShortcutInfo#setLongLived() ShortcutInfo#setLongLived()" in android.app.Notification.MessagingStyle [101]
+android/app/admin/DevicePolicyManager.java:2670: lint: Unresolved link/see tag "android.os.UserManager#DISALLOW_CAMERA UserManager#DISALLOW_CAMERA" in android.app.admin.DevicePolicyManager [101]
+android/app/admin/DevicePolicyManager.java:7257: lint: Unresolved link/see tag "android.app.admin.DevicePolicyIdentifiers#USB_DATA_SIGNALING_POLICY DevicePolicyIdentifiers#USB_DATA_SIGNALING_POLICY" in android.app.admin.DevicePolicyManager [101]
+android/app/admin/DevicePolicyManager.java:7425: lint: Unresolved link/see tag "ACTION_DEVICE_FINANCING_STATE_CHANGED" in android.app.admin.DevicePolicyManager [101]
+android/app/admin/DevicePolicyManager.java:7425: lint: Unresolved link/see tag "android.app.role.RoleManager#ROLE_FINANCED_DEVICE_KIOSK" in android.app.admin.DevicePolicyManager [101]
+android/app/admin/DevicePolicyManager.java:7428: lint: Unresolved link/see tag "android.app.role.RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT" in android.app.admin.DevicePolicyManager [101]
+android/app/admin/DevicePolicyManager.java:8860: lint: Unresolved link/see tag "android.app.admin.DevicePolicyResources.Drawables DevicePolicyResources.Drawables" in android.app.admin.DevicePolicyManager [101]
+android/app/admin/DevicePolicyManager.java:8860: lint: Unresolved link/see tag "android.app.admin.DevicePolicyResources.Strings DevicePolicyResources.Strings" in android.app.admin.DevicePolicyManager [101]
+android/app/admin/DevicePolicyResourcesManager.java:179: lint: Unresolved link/see tag "android.app.admin.DevicePolicyResources.Strings DevicePolicyResources.Strings" in android.app.admin.DevicePolicyResourcesManager [101]
+android/app/appsearch/AppSearchSchema.java:402: lint: Unresolved link/see tag "#getIndexableNestedProperties()" in android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder [101]
+android/app/appsearch/AppSearchSession.java:55: lint: Unresolved link/see tag "Features#LIST_FILTER_QUERY_LANGUAGE" in android.app.appsearch.AppSearchSession [101]
+android/app/appsearch/AppSearchSession.java:55: lint: Unresolved link/see tag "Features#NUMERIC_SEARCH" in android.app.appsearch.AppSearchSession [101]
+android/app/appsearch/AppSearchSession.java:55: lint: Unresolved link/see tag "Features#VERBATIM_SEARCH" in android.app.appsearch.AppSearchSession [101]
+android/app/appsearch/AppSearchSession.java:55: lint: Unresolved link/see tag "Features#isFeatureSupported" in android.app.appsearch.AppSearchSession [101]
+android/app/appsearch/JoinSpec.java:219: lint: Unresolved link/see tag "android.app.appsearch.SearchSpec.RankingStrategy#RANKING_STRATEGY_JOIN_AGGREGATE_SCORE SearchSpec.RankingStrategy#RANKING_STRATEGY_JOIN_AGGREGATE_SCORE" in android.app.appsearch.JoinSpec.Builder [101]
+android/app/appsearch/SearchSpec.java:230: lint: Unresolved link/see tag "Features#NUMERIC_SEARCH" in android.app.appsearch.SearchSpec [101]
+android/app/appsearch/SearchSpec.java:237: lint: Unresolved link/see tag "Features#VERBATIM_SEARCH" in android.app.appsearch.SearchSpec [101]
+android/app/appsearch/SearchSpec.java:244: lint: Unresolved link/see tag "Features#LIST_FILTER_QUERY_LANGUAGE" in android.app.appsearch.SearchSpec [101]
+android/app/appsearch/SearchSpec.java:913: lint: Unresolved link/see tag "Features#NUMERIC_SEARCH" in android.app.appsearch.SearchSpec.Builder [101]
+android/app/appsearch/SearchSpec.java:925: lint: Unresolved link/see tag "Features#VERBATIM_SEARCH" in android.app.appsearch.SearchSpec.Builder [101]
+android/app/appsearch/SearchSpec.java:929: lint: Unresolved link/see tag "Features#LIST_FILTER_QUERY_LANGUAGE" in android.app.appsearch.SearchSpec.Builder [101]
+android/app/job/JobParameters.java:128: lint: Unresolved link/see tag "android.app.job.JobInfo.Builder#setPeriodic(boolean) periodic jobs" in android.app.job.JobParameters [101]
+android/app/sdksandbox/AppOwnedSdkSandboxInterface.java:9: lint: Unresolved link/see tag "SdkSandboxController#getAppOwnedSdkSandboxInterfaces" in android.app.sdksandbox.AppOwnedSdkSandboxInterface [101]
+android/app/sdksandbox/SdkSandboxManager.java:112: lint: Unresolved link/see tag "AppOwnedSdkSandboxInterfaces" in android.app.sdksandbox.SdkSandboxManager [101]
+android/companion/CompanionDeviceService.java:273: lint: Unresolved link/see tag "android.companion.AssociationInfo#isSelfManaged() self-managed" in android.companion.CompanionDeviceService [101]
+android/companion/CompanionDeviceService.java:282: lint: Unresolved link/see tag "android.companion.AssociationInfo#isSelfManaged() self-managed" in android.companion.CompanionDeviceService [101]
+android/companion/virtual/VirtualDevice.java:15: lint: Unresolved link/see tag "android.companion.virtual.VirtualDeviceManager.VirtualDevice VirtualDeviceManager.VirtualDevice" in android.companion.virtual.VirtualDevice [101]
+android/companion/virtual/VirtualDevice.java:70: lint: Unresolved link/see tag "android.companion.virtual.VirtualDeviceParams.Builder#setName(String)" in android.companion.virtual.VirtualDevice [101]
+android/content/AttributionSource.java:291: lint: Unresolved link/see tag "setNextAttributionSource" in android.content.AttributionSource.Builder [101]
+android/content/Context.java:2872: lint: Unresolved link/see tag "android.telephony.MmsManager" in android.content.Context [101]
+android/content/Intent.java:4734: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101]
+android/content/Intent.java:4760: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101]
+android/content/Intent.java:4778: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101]
+android/content/Intent.java:4802: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101]
+android/content/om/OverlayIdentifier.java:20: lint: Unresolved link/see tag "android.content.om.OverlayManagerTransaction.Builder#unregisterFabricatedOverlay(OverlayIdentifier)" in android.content.om.OverlayIdentifier [101]
+android/content/om/OverlayInfo.java:78: lint: Unresolved link/see tag "android.content.om.OverlayManagerTransaction.Builder#unregisterFabricatedOverlay(OverlayIdentifier)" in android.content.om.OverlayInfo [101]
+android/content/om/OverlayManager.java:9: lint: Unresolved link/see tag "android.content.om.OverlayManagerTransaction#commit()" in android.content.om.OverlayManager [101]
+android/content/pm/PackageInstaller.java:2232: lint: Unresolved link/see tag "android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS INSTALL_GRANT_RUNTIME_PERMISSIONS" in android.content.pm.PackageInstaller.SessionParams [101]
+android/content/pm/ServiceInfo.java:176: lint: Unresolved link/see tag "android.app.job.JobInfo.Builder#setDataTransfer" in android.content.pm.ServiceInfo [101]
+android/content/pm/verify/domain/DomainVerificationUserState.java:82: lint: Unresolved link/see tag "android.content.pm.verify.domain.DomainVerificationUserState.DomainState DomainState" in android.content.pm.verify.domain.DomainVerificationUserState [101]
+android/content/res/Resources.java:958: lint: Unresolved link/see tag "android.annotation.UiContext" in android.content.res.Resources [101]
+android/credentials/CreateCredentialException.java:22: lint: Unresolved link/see tag "android.credentials.CredentialManager#createCredential(android.credentials.CreateCredentialRequest,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#createCredential(CreateCredentialRequest, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.CreateCredentialException [101]
+android/credentials/CreateCredentialException.java:101: lint: Unresolved link/see tag "android.credentials.CredentialManager#createCredential(android.credentials.CreateCredentialRequest,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#createCredential(CreateCredentialRequest, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.CreateCredentialException [101]
+android/credentials/CreateCredentialRequest.java:107: lint: Unresolved link/see tag "androidx.credentials.CreateCredentialRequest" in android.credentials.CreateCredentialRequest.Builder [101]
+android/credentials/CredentialDescription.java:89: lint: Unresolved link/see tag "android.credentials.CredentialDescription#mSupportedElementKeys CredentialDescription#mSupportedElementKeys" in android.credentials.CredentialDescription [101]
+android/credentials/CredentialDescription.java:89: lint: Unresolved link/see tag "android.credentials.CredentialDescription#mType CredentialDescription#mType" in android.credentials.CredentialDescription [101]
+android/credentials/CredentialDescription.java:101: lint: Unresolved link/see tag "android.credentials.CredentialDescription#mSupportedElementKeys CredentialDescription#mSupportedElementKeys" in android.credentials.CredentialDescription [101]
+android/credentials/CredentialDescription.java:101: lint: Unresolved link/see tag "android.credentials.CredentialDescription#mType CredentialDescription#mType" in android.credentials.CredentialDescription [101]
+android/credentials/GetCredentialException.java:22: lint: Unresolved link/see tag "android.credentials.CredentialManager#getCredential(android.credentials.GetCredentialRequest,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#getCredential(GetCredentialRequest, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.GetCredentialException [101]
+android/credentials/GetCredentialException.java:103: lint: Unresolved link/see tag "android.credentials.CredentialManager#getCredential(android.credentials.GetCredentialRequest,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver)" in android.credentials.GetCredentialException [101]
+android/credentials/PrepareGetCredentialResponse.java:20: lint: Unresolved link/see tag "android.credentials.CredentialManager#getCredential(android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#getCredential(PendingGetCredentialHandle, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.PrepareGetCredentialResponse [101]
+android/credentials/PrepareGetCredentialResponse.java:68: lint: Unresolved link/see tag "android.credentials.CredentialManager#getCredential(android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#getCredential(PendingGetCredentialHandle, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.PrepareGetCredentialResponse [101]
+android/credentials/PrepareGetCredentialResponse.java:83: lint: Unresolved link/see tag "android.credentials.CredentialManager#getCredential(android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver)" in android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle [101]
+android/graphics/Paint.java:838: lint: Unresolved link/see tag "android.annotation.ColorLong ColorLong" in android.graphics.Paint [101]
+android/graphics/text/LineBreaker.java:246: lint: Unresolved link/see tag "StaticLayout.Builder#setUseBoundsForWidth(boolean)" in android.graphics.text.LineBreaker.Builder [101]
+android/hardware/camera2/CameraCharacteristics.java:2169: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2344: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2344: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations tables" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2361: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors guideline" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2361: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors tables" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2361: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2390: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#preview-stabilization-guaranteed-stream-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2390: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#preview-stabilization-guaranteed-stream-configurations tables" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2402: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2402: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations tables" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2445: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2445: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations tables" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2473: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2473: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraCharacteristics.java:2473: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations tables" in android.hardware.camera2.CameraCharacteristics [101]
+android/hardware/camera2/CameraMetadata.java:1934: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#level-3-additional-guaranteed-configurations" in android.hardware.camera2.CameraMetadata [101]
+android/hardware/camera2/CameraMetadata.java:1980: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#full-level-additional-guaranteed-configurations" in android.hardware.camera2.CameraMetadata [101]
+android/hardware/camera2/CameraMetadata.java:2019: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations" in android.hardware.camera2.CameraMetadata [101]
+android/hardware/camera2/CameraMetadata.java:2038: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#limited-level-additional-guaranteed-configurations" in android.hardware.camera2.CameraMetadata [101]
+android/hardware/camera2/CameraMetadata.java:2533: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations" in android.hardware.camera2.CameraMetadata [101]
+android/hardware/camera2/CameraMetadata.java:3095: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations" in android.hardware.camera2.CameraMetadata [101]
+android/hardware/camera2/CaptureRequest.java:704: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureRequest [101]
+android/hardware/camera2/CaptureRequest.java:1501: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureRequest [101]
+android/hardware/camera2/CaptureResult.java:923: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureResult [101]
+android/hardware/camera2/CaptureResult.java:2337: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureResult [101]
+android/hardware/input/InputManager.java:215: lint: Unresolved link/see tag "android.hardware.input.InputManagerGlobal#getInputDevice InputManagerGlobal#getInputDevice" in android.hardware.input.InputManager.InputDeviceListener [101]
+android/inputmethodservice/AbstractInputMethodService.java:155: lint: Unresolved link/see tag "android.app.ActivityThread ActivityThread" in android.inputmethodservice.AbstractInputMethodService [101]
+android/inputmethodservice/InputMethodService.java:1078: lint: Unresolved link/see tag "android.widget.Editor" in android.inputmethodservice.InputMethodService [101]
+android/location/GnssSignalType.java:14: lint: Unresolved link/see tag "android.location.GnssStatus.ConstellationType GnssStatus.ConstellationType" in android.location.GnssSignalType [101]
+android/location/GnssSignalType.java:48: lint: Unresolved link/see tag "android.location.GnssStatus.ConstellationType GnssStatus.ConstellationType" in android.location.GnssSignalType [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ALARM AttributeSdkUsage#USAGE_ALARM" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ASSISTANCE_ACCESSIBILITY AttributeSdkUsage#USAGE_ASSISTANCE_ACCESSIBILITY" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE AttributeSdkUsage#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ASSISTANCE_SONIFICATION AttributeSdkUsage#USAGE_ASSISTANCE_SONIFICATION" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ASSISTANT AttributeSdkUsage#USAGE_ASSISTANT" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_GAME AttributeSdkUsage#USAGE_GAME" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_MEDIA AttributeSdkUsage#USAGE_MEDIA" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_NOTIFICATION_EVENT AttributeSdkUsage#USAGE_NOTIFICATION_EVENT" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_NOTIFICATION_RINGTONE AttributeSdkUsage#USAGE_NOTIFICATION_RINGTONE" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_UNKNOWN AttributeSdkUsage#USAGE_UNKNOWN" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_VOICE_COMMUNICATION AttributeSdkUsage#USAGE_VOICE_COMMUNICATION" in android.media.AudioAttributes.Builder [101]
+android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_VOICE_COMMUNICATION_SIGNALLING AttributeSdkUsage#USAGE_VOICE_COMMUNICATION_SIGNALLING" in android.media.AudioAttributes.Builder [101]
+android/media/AudioFormat.java:963: lint: Unresolved link/see tag "android.media.AudioSystem#OUT_CHANNEL_COUNT_MAX AudioSystem#OUT_CHANNEL_COUNT_MAX" in android.media.AudioFormat.Builder [101]
+android/media/AudioManager.java:275: lint: Unresolved link/see tag "android.media.audiopolicy.AudioVolumeGroup" in android.media.AudioManager [101]
+android/media/AudioManager.java:287: lint: Unresolved link/see tag "android.media.audiopolicy.AudioVolumeGroup" in android.media.AudioManager [101]
+android/media/AudioManager.java:311: lint: Unresolved link/see tag "android.media.audiopolicy.AudioVolumeGroup" in android.media.AudioManager [101]
+android/media/AudioManager.java:313: lint: Unresolved link/see tag "android.media.audiopolicy.AudioVolumeGroup" in android.media.AudioManager [101]
+android/media/AudioMetadata.java:118: lint: Unresolved link/see tag "android.media.AudioPresentation.ContentClassifier One of {@link android.media.AudioPresentation#CONTENT_UNKNOWN AudioPresentation#CONTENT_UNKNOWN},     {@link android.media.AudioPresentation#CONTENT_MAIN AudioPresentation#CONTENT_MAIN},     {@link android.media.AudioPresentation#CONTENT_MUSIC_AND_EFFECTS AudioPresentation#CONTENT_MUSIC_AND_EFFECTS},     {@link android.media.AudioPresentation#CONTENT_VISUALLY_IMPAIRED AudioPresentation#CONTENT_VISUALLY_IMPAIRED},     {@link android.media.AudioPresentation#CONTENT_HEARING_IMPAIRED AudioPresentation#CONTENT_HEARING_IMPAIRED},     {@link android.media.AudioPresentation#CONTENT_DIALOG AudioPresentation#CONTENT_DIALOG},     {@link android.media.AudioPresentation#CONTENT_COMMENTARY AudioPresentation#CONTENT_COMMENTARY},     {@link android.media.AudioPresentation#CONTENT_EMERGENCY AudioPresentation#CONTENT_EMERGENCY},     {@link android.media.AudioPresentation#CONTENT_VOICEOVER AudioPresentation#CONTENT_VOICEOVER}." in android.media.AudioMetadata.Format [101]
+android/media/MediaRouter2.java:162: lint: Unresolved link/see tag "#getInstance(android.content.Context,java.lang.String)" in android.media.MediaRouter2 [101]
+android/media/midi/MidiUmpDeviceService.java:-1: lint: Unresolved link/see tag "#MidiDeviceService" in android.media.midi.MidiUmpDeviceService [101]
+android/media/tv/SectionRequest.java:44: lint: Unresolved link/see tag "android.media.tv.BroadcastInfoRequest.RequestOption BroadcastInfoRequest.RequestOption" in android.media.tv.SectionRequest [101]
+android/media/tv/SectionResponse.java:39: lint: Unresolved link/see tag "android.media.tv.BroadcastInfoRequest.RequestOption BroadcastInfoRequest.RequestOption" in android.media.tv.SectionResponse [101]
+android/media/tv/TableRequest.java:48: lint: Unresolved link/see tag "android.media.tv.BroadcastInfoRequest.RequestOption BroadcastInfoRequest.RequestOption" in android.media.tv.TableRequest [101]
+android/media/tv/TableResponse.java:82: lint: Unresolved link/see tag "android.media.tv.BroadcastInfoRequest.RequestOption BroadcastInfoRequest.RequestOption" in android.media.tv.TableResponse [101]
+android/net/EthernetNetworkSpecifier.java:21: lint: Unresolved link/see tag "android.net.EthernetManager" in android.net.EthernetNetworkSpecifier [101]
+android/net/eap/EapSessionConfig.java:120: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.Builder [101]
+android/net/eap/EapSessionConfig.java:135: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.Builder [101]
+android/net/eap/EapSessionConfig.java:148: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.Builder [101]
+android/net/eap/EapSessionConfig.java:161: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.Builder [101]
+android/net/eap/EapSessionConfig.java:288: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.EapAkaConfig [101]
+android/net/eap/EapSessionConfig.java:390: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.EapAkaPrimeConfig [101]
+android/net/eap/EapSessionConfig.java:587: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.EapSimConfig [101]
+android/net/wifi/MloLink.java:32: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.MloLink [101]
+android/net/wifi/MloLink.java:32: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.MloLink [101]
+android/net/wifi/MloLink.java:32: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_6_GHZ WifiScanner#WIFI_BAND_6_GHZ" in android.net.wifi.MloLink [101]
+android/net/wifi/MloLink.java:32: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_UNSPECIFIED WifiScanner#WIFI_BAND_UNSPECIFIED" in android.net.wifi.MloLink [101]
+android/net/wifi/SoftApConfiguration.java:9: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder SoftApConfiguration.Builder" in android.net.wifi.SoftApConfiguration [101]
+android/net/wifi/SoftApConfiguration.java:66: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setSsid(java.lang.String) Builder#setSsid(String)" in android.net.wifi.SoftApConfiguration [101]
+android/net/wifi/SoftApConfiguration.java:85: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setWifiSsid(android.net.wifi.WifiSsid) Builder#setWifiSsid(WifiSsid)" in android.net.wifi.SoftApConfiguration [101]
+android/net/wifi/SoftApConfiguration.java:96: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setBssid(android.net.MacAddress) Builder#setBssid(MacAddress)" in android.net.wifi.SoftApConfiguration [101]
+android/net/wifi/SoftApConfiguration.java:107: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setPassphrase(java.lang.String,int) Builder#setPassphrase(String, int)" in android.net.wifi.SoftApConfiguration [101]
+android/net/wifi/SoftApConfiguration.java:118: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setHiddenSsid(boolean) Builder#setHiddenSsid(boolean)" in android.net.wifi.SoftApConfiguration [101]
+android/net/wifi/WifiManager.java:764: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setBands(int[]) SoftApConfiguration.Builder#setBands(int[])" in android.net.wifi.WifiManager [101]
+android/net/wifi/WifiManager.java:764: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray) SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)" in android.net.wifi.WifiManager [101]
+android/net/wifi/WifiManager.java:779: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setBands(int[]) SoftApConfiguration.Builder#setBands(int[])" in android.net.wifi.WifiManager [101]
+android/net/wifi/WifiManager.java:779: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray) SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)" in android.net.wifi.WifiManager [101]
+android/net/wifi/WifiManager.java:2466: lint: Unresolved link/see tag "TelephonyManager#hasCarrierPrivileges()." in android.net.wifi.WifiManager [101]
+android/net/wifi/aware/PublishConfig.java:50: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.PublishConfig [101]
+android/net/wifi/aware/PublishConfig.java:50: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.PublishConfig [101]
+android/net/wifi/aware/PublishConfig.java:249: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.PublishConfig.Builder [101]
+android/net/wifi/aware/PublishConfig.java:249: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.PublishConfig.Builder [101]
+android/net/wifi/aware/SubscribeConfig.java:51: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.SubscribeConfig [101]
+android/net/wifi/aware/SubscribeConfig.java:51: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.SubscribeConfig [101]
+android/net/wifi/aware/SubscribeConfig.java:276: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.SubscribeConfig.Builder [101]
+android/net/wifi/aware/SubscribeConfig.java:276: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.SubscribeConfig.Builder [101]
+android/os/BugreportManager.java:146: lint: Unresolved link/see tag "android.os.BugreportParams#BUGREPORT_FLAG_DEFER_CONSENT BugreportParams#BUGREPORT_FLAG_DEFER_CONSENT" in android.os.BugreportManager.BugreportCallback [101]
+android/os/PowerManager.java:796: lint: Unresolved link/see tag "android.os.Temperature" in android.os.PowerManager.OnThermalStatusChangedListener [101]
+android/os/RemoteException.java:49: lint: Unresolved link/see tag "android.os.DeadSystemRuntimeException DeadSystemRuntimeException" in android.os.RemoteException [101]
+android/provider/Settings.java:374: lint: Unresolved link/see tag "android.credentials.CredentialManager#isEnabledCredentialProviderService()" in android.provider.Settings [101]
+android/provider/Settings.java:908: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService" in android.provider.Settings [101]
+android/provider/Settings.java:2181: lint: Unresolved link/see tag "android.app.time.TimeManager" in android.provider.Settings.Global [101]
+android/provider/Settings.java:2195: lint: Unresolved link/see tag "android.app.time.TimeManager" in android.provider.Settings.Global [101]
+android/security/KeyStoreException.java:27: lint: Unresolved link/see tag "android.security.KeyStoreException.PublicErrorCode PublicErrorCode" in android.security.KeyStoreException [101]
+android/service/autofill/FillResponse.java:86: lint: Unresolved link/see tag "setFieldClassificationIds" in android.service.autofill.FillResponse.Builder [101]
+android/service/autofill/SaveInfo.java:623: lint: Unresolved link/see tag "FillRequest.getHints()" in android.service.autofill.SaveInfo.Builder [101]
+android/service/credentials/Action.java:3: lint: Unresolved link/see tag "androidx.credentials.provider" in android.service.credentials.Action [101]
+android/service/credentials/Action.java:3: lint: Unresolved link/see tag "androidx.credentials.provider.Action" in android.service.credentials.Action [101]
+android/service/credentials/BeginCreateCredentialResponse.java:85: lint: Unresolved link/see tag "Manifest.permission.PROVIDE_REMOTE_CREDENTIALS" in android.service.credentials.BeginCreateCredentialResponse.Builder [101]
+android/service/credentials/BeginGetCredentialResponse.java:80: lint: Unresolved link/see tag "Manifest.permission.PROVIDE_REMOTE_CREDENTIALS" in android.service.credentials.BeginGetCredentialResponse.Builder [101]
+android/service/credentials/CallingAppInfo.java:73: lint: Unresolved link/see tag "android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN" in android.service.credentials.CallingAppInfo [101]
+android/service/credentials/CreateEntry.java:6: lint: Unresolved link/see tag "androidx.credentials.provider" in android.service.credentials.CreateEntry [101]
+android/service/credentials/CreateEntry.java:6: lint: Unresolved link/see tag "androidx.credentials.provider.CreateEntry" in android.service.credentials.CreateEntry [101]
+android/service/credentials/CredentialEntry.java:11: lint: Unresolved link/see tag "androidx.credentials.provider" in android.service.credentials.CredentialEntry [101]
+android/service/credentials/CredentialEntry.java:11: lint: Unresolved link/see tag "androidx.credentials.provider.CredentialEntry" in android.service.credentials.CredentialEntry [101]
+android/service/credentials/RemoteEntry.java:13: lint: Unresolved link/see tag "androidx.credentials.provider" in android.service.credentials.RemoteEntry [101]
+android/service/credentials/RemoteEntry.java:13: lint: Unresolved link/see tag "androidx.credentials.provider.RemoteEntry" in android.service.credentials.RemoteEntry [101]
+android/service/notification/NotificationListenerService.java:417: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService notification assistant" in android.service.notification.NotificationListenerService [101]
+android/service/notification/NotificationListenerService.java:435: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService notification assistant" in android.service.notification.NotificationListenerService [101]
+android/service/notification/NotificationListenerService.java:1155: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService NotificationAssistantService" in android.service.notification.NotificationListenerService.Ranking [101]
+android/service/notification/NotificationListenerService.java:1166: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService NotificationAssistantService" in android.service.notification.NotificationListenerService.Ranking [101]
+android/service/quickaccesswallet/WalletCard.java:285: lint: Unresolved link/see tag "PackageManager.FEATURE_WALLET_LOCATION_BASED_SUGGESTIONS" in android.service.quickaccesswallet.WalletCard.Builder [101]
+android/service/voice/VoiceInteractionSession.java:293: lint: Unresolved link/see tag "android.service.voice.VoiceInteractionService#KEY_SHOW_SESSION_ID VoiceInteractionService#KEY_SHOW_SESSION_ID" in android.service.voice.VoiceInteractionSession [101]
+android/text/DynamicLayout.java:141: lint: Unresolved link/see tag "LineBreakconfig" in android.text.DynamicLayout [101]
+android/text/WordSegmentFinder.java:13: lint: Unresolved link/see tag "android.text.method.WordIterator WordIterator" in android.text.WordSegmentFinder [101]
+android/view/InputDevice.java:71: lint: Unresolved link/see tag "InputManagerGlobal.InputDeviceListener" in android.view.InputDevice [101]
+android/view/PixelCopy.java:468: lint: Unresolved link/see tag "android.view.PixelCopy.CopyResultStatus CopyResultStatus" in android.view.PixelCopy.Result [101]
+android/view/ScrollFeedbackProvider.java:-25: lint: Unresolved link/see tag "InputManager" in android.view.ScrollFeedbackProvider [101]
+android/view/ScrollFeedbackProvider.java:-25: lint: Unresolved link/see tag "InputManager#getInputDeviceIds()" in android.view.ScrollFeedbackProvider [101]
+android/view/SurfaceControl.java:823: lint: Unresolved link/see tag "android.view.SurfaceControl.TrustedPresentationCallback TrustedPresentationCallback" in android.view.SurfaceControl.Transaction [101]
+android/view/SurfaceControl.java:900: lint: Unresolved link/see tag "android.view.SurfaceControl.TrustedPresentationCallback TrustedPresentationCallback" in android.view.SurfaceControl.Transaction [101]
+android/view/SurfaceControl.java:908: lint: Unresolved link/see tag "android.view.SurfaceControl.TrustedPresentationCallback TrustedPresentationCallback" in android.view.SurfaceControl.Transaction [101]
+android/view/View.java:1647: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#setAccessibilityPaneTitle(View, CharSequence)" in android.view.View [101]
+android/view/View.java:4669: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#setScreenReaderFocusable(View, boolean)" in android.view.View [101]
+android/view/View.java:4712: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#setAccessibilityHeading(View, boolean)" in android.view.View [101]
+android/view/WindowManager.java:230: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowManager [101]
+android/view/WindowManager.java:247: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowManager [101]
+android/view/WindowManager.java:822: lint: @attr must be a field: android.R.attr#Window_windowNoMoveAnimation [106]
+android/view/WindowManager.java:832: lint: @attr must be a field: android.R.attr#Window_windowNoMoveAnimation [106]
+android/view/WindowMetrics.java:22: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowMetrics [101]
+android/view/WindowMetrics.java:57: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowMetrics [101]
+android/view/WindowMetrics.java:114: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowMetrics [101]
+android/view/WindowMetrics.java:127: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowMetrics [101]
+android/view/accessibility/AccessibilityNodeInfo.java:368: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#addAccessibilityAction(View, AccessibilityNodeInfoCompat.AccessibilityActionCompat)" in android.view.accessibility.AccessibilityNodeInfo [101]
+android/view/accessibility/AccessibilityNodeInfo.java:3246: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#addAccessibilityAction(View, AccessibilityNodeInfoCompat.AccessibilityActionCompat)" in android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction [101]
+android/view/displayhash/DisplayHashResultCallback.java:38: lint: Unresolved link/see tag "android.view.displayhash.DisplayHashResultCallback.DisplayHashErrorCode DisplayHashErrorCode" in android.view.displayhash.DisplayHashResultCallback [101]
+android/view/inputmethod/EditorInfo.java:107: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.EditorInfo [101]
+android/view/inputmethod/EditorInfo.java:122: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.EditorInfo [101]
+android/view/inputmethod/InputMethodManager.java:423: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.InputMethodManager [101]
+android/view/inputmethod/InputMethodManager.java:447: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.InputMethodManager [101]
+android/view/inputmethod/InputMethodManager.java:456: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.InputMethodManager [101]
+android/view/inspector/PropertyReader.java:141: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.view.inspector.PropertyReader [101]
+android/window/BackEvent.java:24: lint: Unresolved link/see tag "android.window.BackMotionEvent BackMotionEvent" in android.window.BackEvent [101]
+
+android/net/wifi/SoftApConfiguration.java:173: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)" in android.net.wifi.SoftApConfiguration [101]
+android/content/pm/ActivityInfo.java:1197: lint: Unresolved link/see tag "android.view.ViewRootImpl" in android.content.pm.ActivityInfo [101]
+android/os/UserManager.java:2384: lint: Unresolved link/see tag "android.annotation.UserHandleAware @UserHandleAware" in android.os.UserManager [101]
+android/os/UserManager.java:2384: lint: Unresolved link/see tag "android.annotation.UserHandleAware#enabledSinceTargetSdkVersion" in android.os.UserManager [101]
+android/service/voice/AlwaysOnHotwordDetector.java:269: lint: Unresolved link/see tag "#initialize( PersistableBundle, SharedMemory, SoundTrigger.ModuleProperties)" in android.service.voice.AlwaysOnHotwordDetector [101]
+android/service/voice/AlwaysOnHotwordDetector.java:269: lint: Unresolved link/see tag "STATE_HARDWARE_UNAVAILABLE" in android.service.voice.AlwaysOnHotwordDetector [101]
+android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "#STATE_ERROR" in android [101]
+android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "Callback#onFailure" in android [101]
+android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "Callback#onUnknownFailure" in android [101]
+android/view/animation/AnimationUtils.java:64: lint: Unresolved link/see tag "Build.VERSION_CODES#VANILLA_ICE_CREAM" in android.view.animation.AnimationUtils [101]
+android/view/contentcapture/ContentCaptureSession.java:188: lint: Unresolved link/see tag "UPSIDE_DOWN_CAKE" in android.view.contentcapture.ContentCaptureSession [101]
+com/android/internal/policy/PhoneWindow.java:172: lint: Unresolved link/see tag "Build.VERSION_CODES#VANILLA_ICE_CREAM" in com.android.internal.policy.PhoneWindow [101]
+
+com/android/server/companion/virtual/VirtualDeviceImpl.java:134: lint: Unresolved link/see tag "DisplayManager" in android [101]
+com/android/server/companion/virtual/VirtualDeviceImpl.java:134: lint: Unresolved link/see tag "VirtualDeviceManager.VirtualDevice" in android [101]
+com/android/server/broadcastradio/aidl/ConversionUtils.java:70: lint: Unresolved link/see tag "IdentifierType#DAB_SID_EXT" in android [101]
+com/android/server/broadcastradio/aidl/ConversionUtils.java:70: lint: Unresolved link/see tag "ProgramSelector#IDENTIFIER_TYPE_DAB_DMB_SID_EXT" in android [101]
+com/android/server/broadcastradio/aidl/ConversionUtils.java:70: lint: Unresolved link/see tag "RadioTuner" in android [101]
+com/android/server/media/MediaSessionRecord.java:104: lint: Unresolved link/see tag "ComponentName" in android [101]
+com/android/server/media/MediaSessionRecord.java:104: lint: Unresolved link/see tag "IllegalArgumentException" in android [101]
+com/android/server/media/MediaSessionRecord.java:104: lint: Unresolved link/see tag "MediaSession#setMediaButtonBroadcastReceiver(ComponentName)" in android [101]
+com/android/server/media/MediaSessionRecord.java:114: lint: Unresolved link/see tag "IllegalArgumentException" in android [101]
+com/android/server/media/MediaSessionRecord.java:114: lint: Unresolved link/see tag "MediaSession#setMediaButtonReceiver(PendingIntent)" in android [101]
+com/android/server/media/MediaSessionRecord.java:114: lint: Unresolved link/see tag "PendingIntent" in android [101]
+com/android/server/pm/PackageInstallerSession.java:313: lint: Unresolved link/see tag "Build.VERSION_CODES#S API 31" in android [101]
+com/android/server/pm/PackageInstallerSession.java:313: lint: Unresolved link/see tag "PackageInstaller.SessionParams#setRequireUserAction" in android [101]
+com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/see tag "#requestUserPreapproval(PreapprovalDetails, IntentSender)" in android [101]
+com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/see tag "Build.VERSION_CODES#UPSIDE_DOWN_CAKE API 34" in android [101]
+com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/see tag "PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean)" in android [101]
+com/android/server/pm/PackageInstallerSession.java:358: lint: Unresolved link/see tag "IntentSender" in android [101]
+com/android/server/devicepolicy/DevicePolicyManagerService.java:860: lint: Unresolved link/see tag "android.security.IKeyChainService#setGrant" in android [101]
+
+android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java:-4: lint: Invalid tag: @Override [131]
+android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java:-1: lint: Invalid tag: @Override [131]
+android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java:2: lint: Invalid tag: @Override [131]
+android/os/BatteryStatsManager.java:260: lint: Invalid tag: @Deprecated [131]
+android/os/BatteryStatsManager.java:275: lint: Invalid tag: @Deprecated [131]
+android/view/WindowManager.java:906: lint: @attr must be a field: android.R.attr#Window_windowNoMoveAnimation [106]
+android/view/WindowManager.java:916: lint: @attr must be a field: android.R.attr#Window_windowNoMoveAnimation [106]
+
+java/lang/ClassLoader.java:853: lint: Unknown tag: @systemProperty [103]
diff --git a/config/preloaded-classes b/config/preloaded-classes
index aa34bad..7f8f5e3 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -6519,12 +6519,6 @@
 android.security.attestationverification.AttestationVerificationManager
 android.security.keymaster.ExportResult$1
 android.security.keymaster.ExportResult
-android.security.keymaster.IKeyAttestationApplicationIdProvider$Stub
-android.security.keymaster.IKeyAttestationApplicationIdProvider
-android.security.keymaster.KeyAttestationApplicationId$1
-android.security.keymaster.KeyAttestationApplicationId
-android.security.keymaster.KeyAttestationPackageInfo$1
-android.security.keymaster.KeyAttestationPackageInfo
 android.security.keymaster.KeyCharacteristics$1
 android.security.keymaster.KeyCharacteristics
 android.security.keymaster.KeymasterArgument$1
@@ -6549,7 +6543,13 @@
 android.security.keystore.BackendBusyException
 android.security.keystore.DelegatingX509Certificate
 android.security.keystore.DeviceIdAttestationException
+android.security.keystore.IKeyAttestationApplicationIdProvider$Stub
+android.security.keystore.IKeyAttestationApplicationIdProvider
+android.security.keystore.KeyAttestationApplicationId$Stub
+android.security.keystore.KeyAttestationApplicationId
 android.security.keystore.KeyAttestationException
+android.security.keystore.KeyAttestationPackageInfo$Stub
+android.security.keystore.KeyAttestationPackageInfo
 android.security.keystore.KeyExpiredException
 android.security.keystore.KeyGenParameterSpec$Builder
 android.security.keystore.KeyGenParameterSpec
@@ -6572,6 +6572,8 @@
 android.security.keystore.KeystoreResponse
 android.security.keystore.ParcelableKeyGenParameterSpec$1
 android.security.keystore.ParcelableKeyGenParameterSpec
+android.security.keystore.Signature$Stub
+android.security.keystore.Signature
 android.security.keystore.SecureKeyImportUnavailableException
 android.security.keystore.StrongBoxUnavailableException
 android.security.keystore.UserAuthArgs
diff --git a/core/api/current.txt b/core/api/current.txt
index 2b50e38..f908d95 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android {
 
   public final class Manifest {
@@ -4463,7 +4465,7 @@
     method public void onProvideAssistData(android.os.Bundle);
     method public android.net.Uri onProvideReferrer();
     method public void onRequestPermissionsResult(int, @NonNull String[], @NonNull int[]);
-    method public void onRequestPermissionsResult(int, @NonNull String[], @NonNull int[], int);
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis") public void onRequestPermissionsResult(int, @NonNull String[], @NonNull int[], int);
     method @CallSuper protected void onRestart();
     method protected void onRestoreInstanceState(@NonNull android.os.Bundle);
     method public void onRestoreInstanceState(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
@@ -4505,7 +4507,7 @@
     method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
     method public void requestFullscreenMode(int, @Nullable android.os.OutcomeReceiver<java.lang.Void,java.lang.Throwable>);
     method public final void requestPermissions(@NonNull String[], int);
-    method public final void requestPermissions(@NonNull String[], int, int);
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis") public final void requestPermissions(@NonNull String[], int, int);
     method public final void requestShowKeyboardShortcuts();
     method @Deprecated public boolean requestVisibleBehind(boolean);
     method public final boolean requestWindowFeature(int);
@@ -4553,7 +4555,7 @@
     method public void setVrModeEnabled(boolean, @NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean shouldDockBigOverlays();
     method public boolean shouldShowRequestPermissionRationale(@NonNull String);
-    method public boolean shouldShowRequestPermissionRationale(@NonNull String, int);
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis") public boolean shouldShowRequestPermissionRationale(@NonNull String, int);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
     method @Deprecated public final void showDialog(int);
@@ -9683,7 +9685,7 @@
     method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @NonNull public int[] getDisplayIds();
     method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public CharSequence getDisplayName();
     method @Nullable public String getName();
-    method @Nullable public String getPersistentDeviceId();
+    method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public String getPersistentDeviceId();
     method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomSensorSupport();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDevice> CREATOR;
@@ -9769,7 +9771,7 @@
     method public int describeContents();
     method public void enforceCallingUid();
     method @Nullable public String getAttributionTag();
-    method public int getDeviceId();
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis") public int getDeviceId();
     method @Nullable public android.content.AttributionSource getNext();
     method @Nullable public String getPackageName();
     method public int getPid();
@@ -9785,7 +9787,7 @@
     ctor public AttributionSource.Builder(@NonNull android.content.AttributionSource);
     method @NonNull public android.content.AttributionSource build();
     method @NonNull public android.content.AttributionSource.Builder setAttributionTag(@Nullable String);
-    method @NonNull public android.content.AttributionSource.Builder setDeviceId(int);
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis") @NonNull public android.content.AttributionSource.Builder setDeviceId(int);
     method @Deprecated @NonNull public android.content.AttributionSource.Builder setNext(@Nullable android.content.AttributionSource);
     method @NonNull public android.content.AttributionSource.Builder setNextAttributionSource(@NonNull android.content.AttributionSource);
     method @NonNull public android.content.AttributionSource.Builder setPackageName(@Nullable String);
@@ -10992,6 +10994,7 @@
     field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
     field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
     field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
+    field @FlaggedApi("android.content.pm.stay_stopped") public static final String ACTION_PACKAGE_UNSTOPPED = "android.intent.action.PACKAGE_UNSTOPPED";
     field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
     field public static final String ACTION_PASTE = "android.intent.action.PASTE";
     field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -12673,6 +12676,7 @@
     method public boolean isDeviceUpgrading();
     method public abstract boolean isInstantApp();
     method public abstract boolean isInstantApp(@NonNull String);
+    method @FlaggedApi("android.content.pm.stay_stopped") public boolean isPackageStopped(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isPackageSuspended(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isPackageSuspended();
     method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String);
@@ -16086,10 +16090,12 @@
     method public String getFontFeatureSettings();
     method public float getFontMetrics(android.graphics.Paint.FontMetrics);
     method public android.graphics.Paint.FontMetrics getFontMetrics();
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public void getFontMetricsForLocale(@NonNull android.graphics.Paint.FontMetrics);
     method public void getFontMetricsInt(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, boolean, @NonNull android.graphics.Paint.FontMetricsInt);
     method public void getFontMetricsInt(@NonNull char[], @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, boolean, @NonNull android.graphics.Paint.FontMetricsInt);
     method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
     method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public void getFontMetricsIntForLocale(@NonNull android.graphics.Paint.FontMetricsInt);
     method public float getFontSpacing();
     method public String getFontVariationSettings();
     method public int getHinting();
@@ -17666,6 +17672,7 @@
     field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1
     field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0
     field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2
+    field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int LINE_BREAK_STYLE_NO_BREAK = 4; // 0x4
     field public static final int LINE_BREAK_STYLE_STRICT = 3; // 0x3
     field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int LINE_BREAK_STYLE_UNSPECIFIED = -1; // 0xffffffff
     field public static final int LINE_BREAK_WORD_STYLE_NONE = 0; // 0x0
@@ -18539,8 +18546,10 @@
     ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Mac);
     ctor @Deprecated public BiometricPrompt.CryptoObject(@NonNull android.security.identity.IdentityCredential);
     ctor public BiometricPrompt.CryptoObject(@NonNull android.security.identity.PresentationSession);
+    ctor @FlaggedApi("android.hardware.biometrics.add_key_agreement_crypto_object") public BiometricPrompt.CryptoObject(@NonNull javax.crypto.KeyAgreement);
     method public javax.crypto.Cipher getCipher();
     method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
+    method @FlaggedApi("android.hardware.biometrics.add_key_agreement_crypto_object") @Nullable public javax.crypto.KeyAgreement getKeyAgreement();
     method public javax.crypto.Mac getMac();
     method @Nullable public android.security.identity.PresentationSession getPresentationSession();
     method public java.security.Signature getSignature();
@@ -28560,6 +28569,8 @@
     method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
     method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
     method public boolean isEnabled();
+    method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionEnabled();
+    method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
     method public boolean isSecureNfcEnabled();
     method public boolean isSecureNfcSupported();
     field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
@@ -31969,6 +31980,7 @@
     field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
     field public static final int BATTERY_PROPERTY_CURRENT_NOW = 2; // 0x2
     field public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5; // 0x5
+    field @FlaggedApi("android.os.state_of_health_public") public static final int BATTERY_PROPERTY_STATE_OF_HEALTH = 10; // 0xa
     field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
     field public static final int BATTERY_STATUS_CHARGING = 2; // 0x2
     field public static final int BATTERY_STATUS_DISCHARGING = 3; // 0x3
@@ -41552,7 +41564,7 @@
     method public android.telecom.GatewayInfo getGatewayInfo();
     method public android.net.Uri getHandle();
     method public int getHandlePresentation();
-    method @NonNull public String getId();
+    method @FlaggedApi("com.android.server.telecom.flags.call_details_id_changes") @NonNull public String getId();
     method public android.os.Bundle getIntentExtras();
     method public final int getState();
     method public android.telecom.StatusHints getStatusHints();
@@ -42982,7 +42994,6 @@
     field public static final String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
     field public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
-    field @Deprecated public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool";
     field public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
     field public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
     field public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool";
@@ -44212,7 +44223,7 @@
     field public static final int OUT_OF_NETWORK = 11; // 0xb
     field public static final int OUT_OF_SERVICE = 18; // 0x12
     field public static final int POWER_OFF = 17; // 0x11
-    field public static final int SATELLITE_ENABLED = 82; // 0x52
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_ENABLED = 82; // 0x52
     field public static final int SERVER_ERROR = 12; // 0xc
     field public static final int SERVER_UNREACHABLE = 9; // 0x9
     field public static final int TIMED_OUT = 13; // 0xd
@@ -44321,7 +44332,7 @@
     method public boolean isNetworkRegistered();
     method public boolean isNetworkRoaming();
     method public boolean isNetworkSearching();
-    method public boolean isNonTerrestrialNetwork();
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public boolean isNonTerrestrialNetwork();
     method @Deprecated public boolean isRegistered();
     method @Deprecated public boolean isRoaming();
     method @Deprecated public boolean isSearching();
@@ -44337,7 +44348,7 @@
     field public static final int NR_STATE_RESTRICTED = 1; // 0x1
     field public static final int SERVICE_TYPE_DATA = 2; // 0x2
     field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
-    field public static final int SERVICE_TYPE_MMS = 6; // 0x6
+    field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SERVICE_TYPE_MMS = 6; // 0x6
     field public static final int SERVICE_TYPE_SMS = 3; // 0x3
     field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
     field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
@@ -44552,7 +44563,7 @@
     method public boolean getRoaming();
     method public int getState();
     method public boolean isSearching();
-    method public boolean isUsingNonTerrestrialNetwork();
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public boolean isUsingNonTerrestrialNetwork();
     method public void setIsManualSelection(boolean);
     method public void setOperatorName(String, String, String);
     method public void setRoaming(boolean);
@@ -44904,7 +44915,7 @@
     method public int getSubscriptionType();
     method public int getUsageSetting();
     method public boolean isEmbedded();
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public boolean isNtn();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public boolean isOnlyNonTerrestrialNetwork();
     method public boolean isOpportunistic();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SubscriptionInfo> CREATOR;
@@ -45338,7 +45349,7 @@
     field public static final int ERI_FLASH = 2; // 0x2
     field public static final int ERI_OFF = 1; // 0x1
     field public static final int ERI_ON = 0; // 0x0
-    field public static final String EVENT_DISPLAY_SOS_MESSAGE = "android.telephony.event.DISPLAY_SOS_MESSAGE";
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final String EVENT_DISPLAY_SOS_MESSAGE = "android.telephony.event.DISPLAY_SOS_MESSAGE";
     field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT";
     field public static final String EXTRA_APN_PROTOCOL = "android.telephony.extra.APN_PROTOCOL";
     field public static final String EXTRA_APN_TYPE = "android.telephony.extra.APN_TYPE";
@@ -46671,10 +46682,10 @@
     method @NonNull public android.text.DynamicLayout.Builder setHyphenationFrequency(int);
     method @NonNull public android.text.DynamicLayout.Builder setIncludePad(boolean);
     method @NonNull public android.text.DynamicLayout.Builder setJustificationMode(int);
-    method @NonNull public android.text.DynamicLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
+    method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.text.DynamicLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
     method @NonNull public android.text.DynamicLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
     method @NonNull public android.text.DynamicLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
-    method @NonNull public android.text.DynamicLayout.Builder setUseBoundsForWidth(boolean);
+    method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.DynamicLayout.Builder setUseBoundsForWidth(boolean);
     method @NonNull public android.text.DynamicLayout.Builder setUseLineSpacingFromFallbacks(boolean);
   }
 
@@ -47198,7 +47209,7 @@
     method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int);
     method public android.text.StaticLayout.Builder setText(CharSequence);
     method @NonNull public android.text.StaticLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
-    method @NonNull public android.text.StaticLayout.Builder setUseBoundsForWidth(boolean);
+    method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.StaticLayout.Builder setUseBoundsForWidth(boolean);
     method @NonNull public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
   }
 
@@ -47911,6 +47922,10 @@
     method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
   }
 
+  @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final class LineBreakConfigSpan.NoBreakSpan extends android.text.style.LineBreakConfigSpan {
+    ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan.NoBreakSpan();
+  }
+
   @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final class LineBreakConfigSpan.NoHyphenationSpan extends android.text.style.LineBreakConfigSpan {
     ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan.NoHyphenationSpan();
   }
@@ -54651,7 +54666,6 @@
 
   public final class AutofillManager {
     method public void cancel();
-    method public void clearAutofillRequestCallback();
     method public void commit();
     method public void disableAutofillServices();
     method @Nullable public android.content.ComponentName getAutofillServiceComponentName();
@@ -54678,7 +54692,6 @@
     method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
     method public void requestAutofill(@NonNull android.view.View);
     method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
-    method @RequiresPermission(android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS) public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback);
     method public void setUserData(@Nullable android.service.autofill.UserData);
     method public boolean showAutofillDialog(@NonNull android.view.View);
     method public boolean showAutofillDialog(@NonNull android.view.View, int);
@@ -54699,10 +54712,6 @@
     field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
   }
 
-  public interface AutofillRequestCallback {
-    method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
-  }
-
   public final class AutofillValue implements android.os.Parcelable {
     method public int describeContents();
     method public static android.view.autofill.AutofillValue forDate(long);
@@ -55154,12 +55163,10 @@
     ctor public InlineSuggestionsRequest.Builder(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder addInlinePresentationSpecs(@NonNull android.widget.inline.InlinePresentationSpec);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest build();
-    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setExtras(@NonNull android.os.Bundle);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlineTooltipPresentationSpec(@NonNull android.widget.inline.InlinePresentationSpec);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setMaxSuggestionCount(int);
-    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setSupportedLocales(@NonNull android.os.LocaleList);
   }
 
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 052d614..81579a2 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android {
 
   public static final class Manifest.permission {
diff --git a/core/api/module-lib-removed.txt b/core/api/module-lib-removed.txt
index d802177..14191eb 100644
--- a/core/api/module-lib-removed.txt
+++ b/core/api/module-lib-removed.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 57e2e73..e2b4e4d 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android.app {
 
   public class Notification implements android.os.Parcelable {
@@ -472,6 +474,10 @@
 
 package android.telephony {
 
+  public class CarrierConfigManager {
+    field @Deprecated public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool";
+  }
+
   public class NetworkScan {
     method @Deprecated public void stop() throws android.os.RemoteException;
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 358c8e7..c001e0e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android {
 
   public static final class Manifest.permission {
@@ -297,6 +299,7 @@
     field public static final String RECEIVE_DATA_ACTIVITY_CHANGE = "android.permission.RECEIVE_DATA_ACTIVITY_CHANGE";
     field public static final String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY";
     field public static final String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
+    field @FlaggedApi("android.permission.flags.voice_activation_permission_apis") public static final String RECEIVE_SANDBOX_TRIGGER_AUDIO = "android.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO";
     field public static final String RECEIVE_WIFI_CREDENTIAL_CHANGE = "android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE";
     field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
     field public static final String RECOVERY = "android.permission.RECOVERY";
@@ -3209,7 +3212,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.input.VirtualTouchscreenConfig);
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
     method public int getDeviceId();
-    method @Nullable public String getPersistentDeviceId();
+    method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public String getPersistentDeviceId();
     method @NonNull public java.util.List<android.companion.virtual.sensor.VirtualSensor> getVirtualSensorList();
     method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
     method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
@@ -3946,7 +3949,7 @@
     field public static final int DELETE_FAILED_OWNER_BLOCKED = -4; // 0xfffffffc
     field public static final int DELETE_KEEP_DATA = 1; // 0x1
     field public static final int DELETE_SUCCEEDED = 1; // 0x1
-    field public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID = "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID";
+    field @FlaggedApi("android.permission.flags.device_aware_permission_apis") public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID = "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID";
     field public static final String EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES";
     field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
     field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
@@ -4529,7 +4532,7 @@
     method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
     method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
-    field public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 128; // 0x80
+    field @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 128; // 0x80
     field public static final int VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED = 65536; // 0x10000
     field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
   }
@@ -9605,6 +9608,7 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
+    method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
@@ -9704,7 +9708,6 @@
     field @RequiresPermission(android.Manifest.permission.BATTERY_STATS) public static final int BATTERY_PROPERTY_CHARGING_POLICY = 9; // 0x9
     field @RequiresPermission(android.Manifest.permission.BATTERY_STATS) public static final int BATTERY_PROPERTY_FIRST_USAGE_DATE = 8; // 0x8
     field @RequiresPermission(android.Manifest.permission.BATTERY_STATS) public static final int BATTERY_PROPERTY_MANUFACTURING_DATE = 7; // 0x7
-    field @RequiresPermission(android.Manifest.permission.BATTERY_STATS) public static final int BATTERY_PROPERTY_STATE_OF_HEALTH = 10; // 0xa
     field public static final int CHARGING_POLICY_ADAPTIVE_AC = 3; // 0x3
     field public static final int CHARGING_POLICY_ADAPTIVE_AON = 2; // 0x2
     field public static final int CHARGING_POLICY_ADAPTIVE_LONGLIFE = 4; // 0x4
@@ -9772,8 +9775,8 @@
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportBleScanResults(@NonNull android.os.WorkSource, int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportBleScanStarted(@NonNull android.os.WorkSource, boolean);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportBleScanStopped(@NonNull android.os.WorkSource, boolean);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void reportBluetoothOff(int, int, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void reportBluetoothOn(int, int, @NonNull String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void reportBluetoothOff(int, int, @NonNull String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void reportBluetoothOn(int, int, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportMobileRadioPowerState(boolean, int);
@@ -13228,7 +13231,7 @@
     method public void requestStreamingState(int);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telecom.StreamingCall> CREATOR;
-    field public static final String EXTRA_CALL_ID = "android.telecom.extra.CALL_ID";
+    field @FlaggedApi("com.android.server.telecom.flags.call_details_id_changes") public static final String EXTRA_CALL_ID = "android.telecom.extra.CALL_ID";
     field public static final int STATE_DISCONNECTED = 3; // 0x3
     field public static final int STATE_HOLDING = 2; // 0x2
     field public static final int STATE_STREAMING = 1; // 0x1
@@ -13709,7 +13712,7 @@
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setIsNonTerrestrialNetwork(boolean);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull public android.telephony.NetworkRegistrationInfo.Builder setIsNonTerrestrialNetwork(boolean);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegisteredPlmn(@Nullable String);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int);
@@ -16679,157 +16682,157 @@
 
 package android.telephony.satellite {
 
-  public final class AntennaDirection implements android.os.Parcelable {
-    method public int describeContents();
-    method public float getX();
-    method public float getY();
-    method public float getZ();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.AntennaDirection> CREATOR;
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class AntennaDirection implements android.os.Parcelable {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int describeContents();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public float getX();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public float getY();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public float getZ();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.AntennaDirection> CREATOR;
   }
 
-  public final class AntennaPosition implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public android.telephony.satellite.AntennaDirection getAntennaDirection();
-    method public int getSuggestedHoldPosition();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.AntennaPosition> CREATOR;
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class AntennaPosition implements android.os.Parcelable {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int describeContents();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public android.telephony.satellite.AntennaDirection getAntennaDirection();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int getSuggestedHoldPosition();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.AntennaPosition> CREATOR;
   }
 
-  public final class PointingInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public float getSatelliteAzimuthDegrees();
-    method public float getSatelliteElevationDegrees();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.PointingInfo> CREATOR;
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class PointingInfo implements android.os.Parcelable {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int describeContents();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public float getSatelliteAzimuthDegrees();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public float getSatelliteElevationDegrees();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.PointingInfo> CREATOR;
   }
 
-  public final class SatelliteCapabilities implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.Map<java.lang.Integer,android.telephony.satellite.AntennaPosition> getAntennaPositionMap();
-    method public int getMaxBytesPerOutgoingDatagram();
-    method @NonNull public java.util.Set<java.lang.Integer> getSupportedRadioTechnologies();
-    method public boolean isPointingRequired();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.SatelliteCapabilities> CREATOR;
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class SatelliteCapabilities implements android.os.Parcelable {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int describeContents();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public java.util.Map<java.lang.Integer,android.telephony.satellite.AntennaPosition> getAntennaPositionMap();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int getMaxBytesPerOutgoingDatagram();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public java.util.Set<java.lang.Integer> getSupportedRadioTechnologies();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public boolean isPointingRequired();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.SatelliteCapabilities> CREATOR;
   }
 
-  public final class SatelliteDatagram implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public byte[] getSatelliteDatagram();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.SatelliteDatagram> CREATOR;
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class SatelliteDatagram implements android.os.Parcelable {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int describeContents();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public byte[] getSatelliteDatagram();
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.SatelliteDatagram> CREATOR;
   }
 
-  public interface SatelliteDatagramCallback {
-    method public void onSatelliteDatagramReceived(long, @NonNull android.telephony.satellite.SatelliteDatagram, int, @NonNull java.util.function.Consumer<java.lang.Void>);
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteDatagramCallback {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteDatagramReceived(long, @NonNull android.telephony.satellite.SatelliteDatagram, int, @NonNull java.util.function.Consumer<java.lang.Void>);
   }
 
-  public final class SatelliteManager {
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class SatelliteManager {
     method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatelliteService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatelliteService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getSatelliteAttachRestrictionReasonsForCarrier(int);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingSatelliteDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatelliteService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteStateCallback);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingSatelliteDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatelliteService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteStateCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
     method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsDemoModeEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsDemoModeEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteAttachEnabledForCarrier(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteCommunicationAllowedForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method public void requestIsSatelliteSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteCommunicationAllowedForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void requestIsSatelliteSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestTimeForNextSatelliteVisibility(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.time.Duration,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void sendSatelliteDatagram(int, @NonNull android.telephony.satellite.SatelliteDatagram, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void setDeviceAlignedWithSatellite(boolean);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void startSatelliteTransmissionUpdates(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void stopSatelliteTransmissionUpdates(@NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteDatagram(@NonNull android.telephony.satellite.SatelliteDatagramCallback);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteModemStateChanged(@NonNull android.telephony.satellite.SatelliteStateCallback);
-    method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
-    field public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2; // 0x2
-    field public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1; // 0x1
-    field public static final int DATAGRAM_TYPE_UNKNOWN = 0; // 0x0
-    field public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2; // 0x2
-    field public static final int DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT = 3; // 0x3
-    field public static final int DEVICE_HOLD_POSITION_PORTRAIT = 1; // 0x1
-    field public static final int DEVICE_HOLD_POSITION_UNKNOWN = 0; // 0x0
-    field public static final int DISPLAY_MODE_CLOSED = 3; // 0x3
-    field public static final int DISPLAY_MODE_FIXED = 1; // 0x1
-    field public static final int DISPLAY_MODE_OPENED = 2; // 0x2
-    field public static final int DISPLAY_MODE_UNKNOWN = 0; // 0x0
-    field public static final int NT_RADIO_TECHNOLOGY_EMTC_NTN = 3; // 0x3
-    field public static final int NT_RADIO_TECHNOLOGY_NB_IOT_NTN = 1; // 0x1
-    field public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2; // 0x2
-    field public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4; // 0x4
-    field public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; // 0x0
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestTimeForNextSatelliteVisibility(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.time.Duration,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void sendSatelliteDatagram(int, @NonNull android.telephony.satellite.SatelliteDatagram, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void setDeviceAlignedWithSatellite(boolean);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void startSatelliteTransmissionUpdates(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void stopSatelliteTransmissionUpdates(@NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteDatagram(@NonNull android.telephony.satellite.SatelliteDatagramCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteModemStateChanged(@NonNull android.telephony.satellite.SatelliteStateCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_UNKNOWN = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DEVICE_HOLD_POSITION_PORTRAIT = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DEVICE_HOLD_POSITION_UNKNOWN = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DISPLAY_MODE_CLOSED = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DISPLAY_MODE_FIXED = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DISPLAY_MODE_OPENED = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DISPLAY_MODE_UNKNOWN = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_EMTC_NTN = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_NB_IOT_NTN = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4; // 0x4
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; // 0x0
     field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1; // 0x1
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; // 0x0
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; // 0x7
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6; // 0x6
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS = 5; // 0x5
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING = 4; // 0x4
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING = 1; // 0x1
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3; // 0x3
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2; // 0x2
-    field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1; // 0xffffffff
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; // 0x7
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6; // 0x6
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS = 5; // 0x5
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING = 4; // 0x4
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1; // 0xffffffff
     field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT = 8; // 0x8
     field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_CONNECTED = 7; // 0x7
-    field public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3; // 0x3
-    field public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2; // 0x2
-    field public static final int SATELLITE_MODEM_STATE_IDLE = 0; // 0x0
-    field public static final int SATELLITE_MODEM_STATE_LISTENING = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_IDLE = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_LISTENING = 1; // 0x1
     field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_NOT_CONNECTED = 6; // 0x6
-    field public static final int SATELLITE_MODEM_STATE_OFF = 4; // 0x4
-    field public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5; // 0x5
-    field public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1; // 0xffffffff
-    field public static final int SATELLITE_RESULT_ACCESS_BARRED = 16; // 0x10
-    field public static final int SATELLITE_RESULT_ERROR = 1; // 0x1
-    field public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8; // 0x8
-    field public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7; // 0x7
-    field public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6; // 0x6
-    field public static final int SATELLITE_RESULT_MODEM_BUSY = 22; // 0x16
-    field public static final int SATELLITE_RESULT_MODEM_ERROR = 4; // 0x4
-    field public static final int SATELLITE_RESULT_NETWORK_ERROR = 5; // 0x5
-    field public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17; // 0x11
-    field public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19; // 0x13
-    field public static final int SATELLITE_RESULT_NOT_REACHABLE = 18; // 0x12
-    field public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20; // 0x14
-    field public static final int SATELLITE_RESULT_NO_RESOURCES = 12; // 0xc
-    field public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10; // 0xa
-    field public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15; // 0xf
-    field public static final int SATELLITE_RESULT_REQUEST_FAILED = 9; // 0x9
-    field public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21; // 0x15
-    field public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11; // 0xb
-    field public static final int SATELLITE_RESULT_SERVER_ERROR = 2; // 0x2
-    field public static final int SATELLITE_RESULT_SERVICE_ERROR = 3; // 0x3
-    field public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13; // 0xd
-    field public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14; // 0xe
-    field public static final int SATELLITE_RESULT_SUCCESS = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_OFF = 4; // 0x4
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5; // 0x5
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1; // 0xffffffff
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_ACCESS_BARRED = 16; // 0x10
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_ERROR = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8; // 0x8
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7; // 0x7
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6; // 0x6
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_MODEM_BUSY = 22; // 0x16
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_MODEM_ERROR = 4; // 0x4
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NETWORK_ERROR = 5; // 0x5
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17; // 0x11
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19; // 0x13
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NOT_REACHABLE = 18; // 0x12
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20; // 0x14
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NO_RESOURCES = 12; // 0xc
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10; // 0xa
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15; // 0xf
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_REQUEST_FAILED = 9; // 0x9
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21; // 0x15
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11; // 0xb
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_SERVER_ERROR = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_SERVICE_ERROR = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13; // 0xd
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14; // 0xe
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_SUCCESS = 0; // 0x0
   }
 
-  public static class SatelliteManager.SatelliteException extends java.lang.Exception {
-    ctor public SatelliteManager.SatelliteException(int);
-    method public int getErrorCode();
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static class SatelliteManager.SatelliteException extends java.lang.Exception {
+    ctor @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public SatelliteManager.SatelliteException(int);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int getErrorCode();
   }
 
-  public interface SatelliteProvisionStateCallback {
-    method public void onSatelliteProvisionStateChanged(boolean);
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteProvisionStateCallback {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteProvisionStateChanged(boolean);
   }
 
-  public interface SatelliteStateCallback {
-    method public void onSatelliteModemStateChanged(int);
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteStateCallback {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteModemStateChanged(int);
   }
 
-  public interface SatelliteTransmissionUpdateCallback {
-    method public void onReceiveDatagramStateChanged(int, int, int);
-    method public void onSatellitePositionChanged(@NonNull android.telephony.satellite.PointingInfo);
-    method public void onSendDatagramStateChanged(int, int, int);
+  @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteTransmissionUpdateCallback {
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onReceiveDatagramStateChanged(int, int, int);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatellitePositionChanged(@NonNull android.telephony.satellite.PointingInfo);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSendDatagramStateChanged(int, int, int);
   }
 
 }
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index aa17df3..1fa2718 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android.app {
 
   public class AppOpsManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 40c6fa8..3716546 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android {
 
   public static final class Manifest.permission {
@@ -875,7 +877,7 @@
     ctor public AttributionSource(int, @Nullable String, @Nullable String, @NonNull android.os.IBinder);
     ctor public AttributionSource(int, @Nullable String, @Nullable String, @Nullable java.util.Set<java.lang.String>, @Nullable android.content.AttributionSource);
     ctor public AttributionSource(int, int, @Nullable String, @Nullable String, @NonNull android.os.IBinder, @Nullable String[], @Nullable android.content.AttributionSource);
-    ctor public AttributionSource(int, int, @Nullable String, @Nullable String, @NonNull android.os.IBinder, @Nullable String[], int, @Nullable android.content.AttributionSource);
+    ctor @FlaggedApi("android.permission.flags.device_aware_permission_apis") public AttributionSource(int, int, @Nullable String, @Nullable String, @NonNull android.os.IBinder, @Nullable String[], int, @Nullable android.content.AttributionSource);
     method public void enforceCallingPid();
   }
 
@@ -1903,7 +1905,7 @@
     method public android.media.PlaybackParams setAudioStretchMode(int);
   }
 
-  public final class RingtoneSelection {
+  @FlaggedApi("android.os.vibrator.haptics_customization_enabled") public final class RingtoneSelection {
     method @NonNull public static android.media.RingtoneSelection fromUri(@Nullable android.net.Uri, int);
     method public int getSoundSource();
     method @Nullable public android.net.Uri getSoundUri();
@@ -1915,14 +1917,16 @@
     field public static final int FROM_URI_RINGTONE_SELECTION_ONLY = 3; // 0x3
     field public static final int FROM_URI_RINGTONE_SELECTION_OR_SOUND = 1; // 0x1
     field public static final int FROM_URI_RINGTONE_SELECTION_OR_VIBRATION = 2; // 0x2
-    field public static final int SOUND_SOURCE_DEFAULT = 0; // 0x0
     field public static final int SOUND_SOURCE_OFF = 1; // 0x1
+    field public static final int SOUND_SOURCE_SYSTEM_DEFAULT = 3; // 0x3
+    field public static final int SOUND_SOURCE_UNSPECIFIED = 0; // 0x0
     field public static final int SOUND_SOURCE_URI = 2; // 0x2
-    field public static final int VIBRATION_SOURCE_APPLICATION_PROVIDED = 3; // 0x3
+    field public static final int VIBRATION_SOURCE_APPLICATION_DEFAULT = 4; // 0x4
     field public static final int VIBRATION_SOURCE_AUDIO_CHANNEL = 10; // 0xa
-    field public static final int VIBRATION_SOURCE_DEFAULT = 0; // 0x0
     field public static final int VIBRATION_SOURCE_HAPTIC_GENERATOR = 11; // 0xb
     field public static final int VIBRATION_SOURCE_OFF = 1; // 0x1
+    field public static final int VIBRATION_SOURCE_SYSTEM_DEFAULT = 3; // 0x3
+    field public static final int VIBRATION_SOURCE_UNSPECIFIED = 0; // 0x0
     field public static final int VIBRATION_SOURCE_URI = 2; // 0x2
   }
 
@@ -2610,17 +2614,17 @@
 
 package android.os.vibrator.persistence {
 
-  public class ParsedVibration {
+  @FlaggedApi("android.os.vibrator.enable_vibration_serialization_apis") public class ParsedVibration {
     method @NonNull public java.util.List<android.os.VibrationEffect> getVibrationEffects();
     method @Nullable public android.os.VibrationEffect resolve(@NonNull android.os.Vibrator);
   }
 
-  public final class VibrationXmlParser {
+  @FlaggedApi("android.os.vibrator.enable_vibration_serialization_apis") public final class VibrationXmlParser {
     method @Nullable public static android.os.vibrator.persistence.ParsedVibration parseDocument(@NonNull java.io.Reader) throws java.io.IOException;
     method @Nullable public static android.os.VibrationEffect parseVibrationEffect(@NonNull java.io.Reader) throws java.io.IOException;
   }
 
-  public final class VibrationXmlSerializer {
+  @FlaggedApi("android.os.vibrator.enable_vibration_serialization_apis") public final class VibrationXmlSerializer {
     method public static void serialize(@NonNull android.os.VibrationEffect, @NonNull java.io.Writer) throws java.io.IOException, android.os.vibrator.persistence.VibrationXmlSerializer.SerializationFailedException;
   }
 
@@ -2955,10 +2959,6 @@
     method @Deprecated public boolean isBound();
   }
 
-  public class NotificationRankingUpdate implements android.os.Parcelable {
-    method public final boolean isFdNotNullAndClosed();
-  }
-
 }
 
 package android.service.quickaccesswallet {
@@ -3188,7 +3188,7 @@
     field public static final int HAL_SERVICE_MESSAGING = 2; // 0x2
     field public static final int HAL_SERVICE_MODEM = 3; // 0x3
     field public static final int HAL_SERVICE_NETWORK = 4; // 0x4
-    field public static final int HAL_SERVICE_SATELLITE = 8; // 0x8
+    field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int HAL_SERVICE_SATELLITE = 8; // 0x8
     field public static final int HAL_SERVICE_SIM = 5; // 0x5
     field public static final int HAL_SERVICE_VOICE = 6; // 0x6
     field public static final android.util.Pair HAL_VERSION_UNKNOWN;
@@ -3281,12 +3281,12 @@
   }
 
   public class MeasuredParagraph {
-    method @NonNull public static android.text.MeasuredParagraph buildForStaticLayoutTest(@NonNull android.text.TextPaint, @Nullable android.graphics.text.LineBreakConfig, @NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextDirectionHeuristic, int, boolean, @Nullable android.text.MeasuredParagraph.StyleRunCallback);
+    method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public static android.text.MeasuredParagraph buildForStaticLayoutTest(@NonNull android.text.TextPaint, @Nullable android.graphics.text.LineBreakConfig, @NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextDirectionHeuristic, int, boolean, @Nullable android.text.MeasuredParagraph.StyleRunCallback);
   }
 
-  public static interface MeasuredParagraph.StyleRunCallback {
-    method public void onAppendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float);
-    method public void onAppendStyleRun(@NonNull android.graphics.Paint, @Nullable android.graphics.text.LineBreakConfig, @IntRange(from=0) int, boolean);
+  @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static interface MeasuredParagraph.StyleRunCallback {
+    method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public void onAppendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float);
+    method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public void onAppendStyleRun(@NonNull android.graphics.Paint, @Nullable android.graphics.text.LineBreakConfig, @IntRange(from=0) int, boolean);
   }
 
   public static final class Selection.MemoryTextWatcher implements android.text.TextWatcher {
@@ -3408,7 +3408,7 @@
 
   public final class Choreographer {
     method public static long getFrameDelay();
-    method public long getFrameTimeNanos();
+    method @FlaggedApi("android.view.flags.expected_presentation_time_api") public long getFrameTimeNanos();
     method public void postCallback(int, Runnable, Object);
     method public void postCallbackDelayed(int, Runnable, Object, long);
     method public void removeCallbacks(int, Runnable, Object);
@@ -3569,8 +3569,8 @@
     method public default void holdLock(android.os.IBinder, int);
     method public default boolean isGlobalKey(int);
     method public default boolean isTaskSnapshotSupported();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_SURFACE_FLINGER) public default boolean replaceContentOnDisplayWithMirror(int, @NonNull android.view.Window);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_SURFACE_FLINGER) public default boolean replaceContentOnDisplayWithSc(int, @NonNull android.view.SurfaceControl);
+    method @FlaggedApi("REPLACE_CONTENT_WITH_MIRROR") @RequiresPermission(android.Manifest.permission.ACCESS_SURFACE_FLINGER) public default boolean replaceContentOnDisplayWithMirror(int, @NonNull android.view.Window);
+    method @FlaggedApi("REPLACE_CONTENT_WITH_MIRROR") @RequiresPermission(android.Manifest.permission.ACCESS_SURFACE_FLINGER) public default boolean replaceContentOnDisplayWithSc(int, @NonNull android.view.SurfaceControl);
     method public default void setDisplayImePolicy(int, int);
     method public default void setShouldShowSystemDecors(int, boolean);
     method public default void setShouldShowWithInsecureKeyguard(int, boolean);
@@ -3627,7 +3627,7 @@
 package android.view.animation {
 
   public class AnimationUtils {
-    method public static void lockAnimationClock(long, long);
+    method @FlaggedApi("android.view.flags.expected_presentation_time_api") public static void lockAnimationClock(long, long);
     method public static void unlockAnimationClock();
   }
 
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 107be8b..93e39d5 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -191,8 +191,14 @@
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_DEFAULT
 UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_OFF:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_OFF
+UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_SYSTEM_DEFAULT:
+    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_SYSTEM_DEFAULT
+UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_UNSPECIFIED:
+    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_UNSPECIFIED
 UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_URI:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_URI
+UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_APPLICATION_DEFAULT:
+    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_APPLICATION_DEFAULT
 UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_APPLICATION_PROVIDED:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_APPLICATION_PROVIDED
 UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_AUDIO_CHANNEL:
@@ -203,6 +209,10 @@
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_HAPTIC_GENERATOR
 UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_OFF:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_OFF
+UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_SYSTEM_DEFAULT:
+    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_SYSTEM_DEFAULT
+UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_UNSPECIFIED:
+    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_UNSPECIFIED
 UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_URI:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_URI
 UnflaggedApi: android.media.RingtoneSelection#fromUri(android.net.Uri, int):
diff --git a/core/api/test-removed.txt b/core/api/test-removed.txt
index d802177..14191eb 100644
--- a/core/api/test-removed.txt
+++ b/core/api/test-removed.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 13a1bd6..0293f66 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -23,11 +23,6 @@
     visibility: ["//frameworks/base"],
 }
 
-filegroup {
-    name: "IKeyAttestationApplicationIdProvider.aidl",
-    srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"],
-}
-
 aidl_library {
     name: "IDropBoxManagerService_aidl",
     srcs: [
@@ -431,6 +426,16 @@
     },
 }
 
+aidl_interface {
+    name: "android.companion.virtual.virtualdevice_aidl",
+    unstable: true,
+    host_supported: true,
+    srcs: [
+        "android/companion/virtualnative/IVirtualDeviceManagerNative.aidl",
+    ],
+    local_include_dir: ".",
+}
+
 filegroup {
     name: "frameworks-base-java-overview",
     srcs: ["overview.html"],
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index e40ea09..3370c12 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -3543,9 +3543,9 @@
      * @param executor Executor on which to run the callback.
      * @param callback The callback invoked when attaching the overlay has succeeded or failed. The
      *     callback is a {@link java.util.function.IntConsumer} of the result status code.
-     * @see OVERLAY_RESULT_SUCCESS
-     * @see OVERLAY_RESULT_INVALID
-     * @see OVERLAY_RESULT_INTERNAL_ERROR
+     * @see #OVERLAY_RESULT_SUCCESS
+     * @see #OVERLAY_RESULT_INVALID
+     * @see #OVERLAY_RESULT_INTERNAL_ERROR
      */
     public void attachAccessibilityOverlayToDisplay(
             int displayId,
@@ -3619,9 +3619,9 @@
      * @param executor Executor on which to run the callback.
      * @param callback The callback invoked when attaching the overlay has succeeded or failed. The
      *     callback is a {@link java.util.function.IntConsumer} of the result status code.
-     * @see OVERLAY_RESULT_SUCCESS
-     * @see OVERLAY_RESULT_INVALID
-     * @see OVERLAY_RESULT_INTERNAL_ERROR
+     * @see #OVERLAY_RESULT_SUCCESS
+     * @see #OVERLAY_RESULT_INVALID
+     * @see #OVERLAY_RESULT_INTERNAL_ERROR
      */
     public void attachAccessibilityOverlayToWindow(
             int accessibilityWindowId,
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 6550f30..3f9cc65 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -1020,7 +1020,6 @@
      *
      * @param motionEventSources A bit mask of {@link android.view.InputDevice} sources.
      * @see AccessibilityService#onMotionEvent
-     * @see #MotionEventSources
      */
     public void setMotionEventSources(@MotionEventSources int motionEventSources) {
         mMotionEventSources = motionEventSources;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7bc6f9bf..e51a41e8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -31,6 +31,7 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
+import android.annotation.FlaggedApi;
 import android.annotation.IdRes;
 import android.annotation.IntDef;
 import android.annotation.LayoutRes;
@@ -98,6 +99,7 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.permission.flags.Flags;
 import android.service.voice.VoiceInteractionSession;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
@@ -5556,8 +5558,7 @@
      *                    reported to {@link #onRequestPermissionsResult}.
      *                    Should be >= 0.
      * @param deviceId The app is requesting permissions for this device. The primary/physical
-     *                 device is assigned {@link Context#DEVICE_ID_DEFAULT}, and {@link
-     *                 android.companion.virtual.VirtualDeviceManager.VirtualDevice virtual devices}
+     *                 device is assigned {@link Context#DEVICE_ID_DEFAULT}, and virtual devices
      *                 are assigned unique device Ids.
      *
      * @throws IllegalArgumentException if requestCode is negative.
@@ -5567,6 +5568,7 @@
      * @see #shouldShowRequestPermissionRationale
      * @see Context#DEVICE_ID_DEFAULT
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)
     public final void requestPermissions(@NonNull String[] permissions, int requestCode,
             int deviceId) {
         if (requestCode < 0) {
@@ -5634,12 +5636,12 @@
      *                     {@link android.content.pm.PackageManager#PERMISSION_GRANTED} or
      *                     {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
      * @param deviceId The deviceId for which permissions were requested. The primary/physical
-     *                 device is assigned {@link Context#DEVICE_ID_DEFAULT}, and {@link
-     *                 android.companion.virtual.VirtualDeviceManager.VirtualDevice virtual devices}
+     *                 device is assigned {@link Context#DEVICE_ID_DEFAULT}, and virtual devices
      *                 are assigned unique device Ids.
      *
      * @see #requestPermissions
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)
     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
             @NonNull int[] grantResults, int deviceId) {
         onRequestPermissionsResult(requestCode, permissions, grantResults);
@@ -5664,8 +5666,7 @@
      *
      * @param permission A permission your app wants to request.
      * @param deviceId The app is requesting permissions for this device. The primary/physical
-     *                 device is assigned {@link Context#DEVICE_ID_DEFAULT}, and {@link
-     *                 android.companion.virtual.VirtualDeviceManager.VirtualDevice virtual devices}
+     *                 device is assigned {@link Context#DEVICE_ID_DEFAULT}, and virtual devices
      *                 are assigned unique device Ids.
      * @return Whether you should show permission rationale UI.
      *
@@ -5673,6 +5674,7 @@
      * @see #requestPermissions
      * @see #onRequestPermissionsResult
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)
     public boolean shouldShowRequestPermissionRationale(@NonNull String permission, int deviceId) {
         final PackageManager packageManager = getDeviceId() == deviceId ? getPackageManager()
                 : createDeviceContext(deviceId).getPackageManager();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 3bf2cca..f68681b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4288,7 +4288,7 @@
     }
 
     /**
-     * Start monitoring changes to the imoportance of uids running in the system.
+     * Start monitoring changes to the importance of uids running in the system.
      * @param listener The listener callback that will receive change reports.
      * @param importanceCutpoint The level of importance in which the caller is interested
      * in differences.  For example, if {@link RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9a90df9..e12181a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -101,6 +101,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.ResourcesImpl;
 import android.content.res.loader.ResourcesLoader;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDebug;
@@ -297,6 +298,7 @@
     public static final boolean DEBUG_MEMORY_TRIM = false;
     private static final boolean DEBUG_PROVIDER = false;
     public static final boolean DEBUG_ORDER = false;
+    private static final boolean DEBUG_APP_INFO = true;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     /**
      * The delay to release the provider when it has no more references. It reduces the number of
@@ -6473,10 +6475,35 @@
             resApk.updateApplicationInfo(ai, oldPaths);
         }
 
+        ResourcesImpl beforeImpl = getApplication().getResources().getImpl();
+
         synchronized (mResourcesManager) {
             // Update all affected Resources objects to use new ResourcesImpl
             mResourcesManager.applyAllPendingAppInfoUpdates();
         }
+
+        ResourcesImpl afterImpl = getApplication().getResources().getImpl();
+
+        if ((beforeImpl != afterImpl) && !Arrays.equals(beforeImpl.getAssets().getApkAssets(),
+                afterImpl.getAssets().getApkAssets())) {
+            List<String> beforeAssets = Arrays.asList(beforeImpl.getAssets().getApkPaths());
+            List<String> afterAssets = Arrays.asList(afterImpl.getAssets().getApkPaths());
+
+            List<String> onlyBefore = new ArrayList<>(beforeAssets);
+            onlyBefore.removeAll(afterAssets);
+            List<String> onlyAfter = new ArrayList<>(afterAssets);
+            onlyAfter.removeAll(beforeAssets);
+
+            Slog.i(TAG, "ApplicationInfo updating for " + ai.packageName + ", new timestamp: "
+                    + ai.createTimestamp + "\nassets removed: " + onlyBefore + "\nassets added: "
+                    + onlyAfter);
+
+            if (DEBUG_APP_INFO) {
+                Slog.v(TAG, "ApplicationInfo updating for " + ai.packageName
+                        + ", assets before change: " + beforeAssets + "\n assets after change: "
+                        + afterAssets);
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ca10d14..6858945 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1478,7 +1478,8 @@
             AppProtoEnums.APP_OP_RECORD_AUDIO_SANDBOXED;
 
     /**
-     * Allows the assistant app to receive the PCC-validated hotword and be voice-triggered.
+     * Allows the assistant app to be voice-triggered by detected hotwords from a trusted detection
+     * service.
      *
      * @hide
      */
@@ -1486,13 +1487,13 @@
             AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
 
     /**
-     * Allows the assistant app to get the training data from the PCC sandbox to improve the
+     * Allows the assistant app to get the training data from the trusted process to improve the
      * hotword training model.
      *
      * @hide
      */
-    public static final int OP_RECEIVE_SANDBOX_TRAINING_DATA =
-            AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRAINING_DATA;
+    public static final int OP_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA =
+            AppProtoEnums.APP_OP_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA;
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1640,7 +1641,7 @@
             OPSTR_CAMERA_SANDBOXED,
             OPSTR_RECORD_AUDIO_SANDBOXED,
             OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
-            OPSTR_RECEIVE_SANDBOX_TRAINING_DATA
+            OPSTR_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA
     })
     public @interface AppOpString {}
 
@@ -2252,7 +2253,8 @@
     public static final String OPSTR_USE_FULL_SCREEN_INTENT = "android:use_full_screen_intent";
 
     /**
-     * Allows the assistant app to receive the PCC-validated hotword and be voice-triggered.
+     * Allows the assistant app to be voice-triggered by detected hotwords from a trusted detection
+     * service.
      *
      * @hide
      */
@@ -2261,13 +2263,13 @@
             "android:receive_sandbox_trigger_audio";
 
     /**
-     * Allows the assistant app to get the training data from the PCC sandbox to improve
+     * Allows the assistant app to get the training data from the trusted process to improve
      * the hotword training model.
      *
      * @hide
      */
-    public static final String OPSTR_RECEIVE_SANDBOX_TRAINING_DATA =
-            "android:receive_sandbox_training_data";
+    public static final String OPSTR_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA =
+            "android:receive_trusted_process_training_data";
 
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
@@ -2379,7 +2381,8 @@
             OP_RUN_USER_INITIATED_JOBS,
             OP_FOREGROUND_SERVICE_SPECIAL_USE,
             OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD,
-            OP_USE_FULL_SCREEN_INTENT
+            OP_USE_FULL_SCREEN_INTENT,
+            OP_RECEIVE_SANDBOX_TRIGGER_AUDIO
     };
 
     static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{
@@ -2810,10 +2813,11 @@
         new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
                 OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
                 "RECEIVE_SANDBOX_TRIGGER_AUDIO")
-                .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
-        new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_TRAINING_DATA,
-                OPSTR_RECEIVE_SANDBOX_TRAINING_DATA,
-                "RECEIVE_SANDBOX_TRAINING_DATA").build()
+                .setPermission(Manifest.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO)
+                .setDefaultMode(AppOpsManager.MODE_DEFAULT).build(),
+        new AppOpInfo.Builder(OP_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA,
+                OPSTR_RECEIVE_TRUSTED_PROCESS_TRAINING_DATA,
+                "RECEIVE_TRUSTED_PROCESS_TRAINING_DATA").build()
     };
 
     // The number of longs needed to form a full bitmask of app ops
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 7b3d017..d15c79f 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -468,6 +468,15 @@
      */
     public static final int SUBREASON_EXCESSIVE_BINDER_OBJECTS = 29;
 
+    /**
+     * The process was killed by the [kernel] Out-of-memory (OOM) killer; this
+     * would be set only when the reason is {@link #REASON_LOW_MEMORY}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_OOM_KILL = 30;
+
     // If there is any OEM code which involves additional app kill reasons, it should
     // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
 
@@ -644,6 +653,7 @@
         SUBREASON_PACKAGE_UPDATE,
         SUBREASON_UNDELIVERED_BROADCAST,
         SUBREASON_EXCESSIVE_BINDER_OBJECTS,
+        SUBREASON_OOM_KILL,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SubReason {}
@@ -1371,6 +1381,8 @@
                 return "UNDELIVERED BROADCAST";
             case SUBREASON_EXCESSIVE_BINDER_OBJECTS:
                 return "EXCESSIVE BINDER OBJECTS";
+            case SUBREASON_OOM_KILL:
+                return "OOM KILL";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index e5a73be..21ed098 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2954,6 +2954,17 @@
         }
     }
 
+    @Override
+    public boolean isPackageStopped(@NonNull String packageName) throws NameNotFoundException {
+        try {
+            return mPM.isPackageStoppedForUser(packageName, getUserId());
+        } catch (IllegalArgumentException ie) {
+            throw new NameNotFoundException(packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     @Override
     public void setApplicationCategoryHint(String packageName, int categoryHint) {
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
index a6a57cd..37111e9 100644
--- a/core/java/android/app/ApplicationStartInfo.java
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -473,9 +473,8 @@
      * available.
      * For {@link #STARTUP_STATE_ERROR}, no additional timestamps are guaranteed available.
      * For {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}, timestamps
-     * {@link #START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE}, {@link #START_TIMESTAMP_APPLICATION_ONCREATE},
-     * {@link #START_TIMESTAMP_BIND_APPLICATION}, and {@link #START_TIMESTAMP_FIRST_FRAME} will
-     * additionally be available.
+     * {@link #START_TIMESTAMP_APPLICATION_ONCREATE}, {@link #START_TIMESTAMP_BIND_APPLICATION},
+     * and {@link #START_TIMESTAMP_FIRST_FRAME} will additionally be available.
      *
      * Timestamp {@link #START_TIMESTAMP_FULLY_DRAWN} is never guaranteed to be available as it is
      * dependant on devloper calling {@link Activity#reportFullyDrawn}.
diff --git a/core/java/android/app/GrammaticalInflectionManager.java b/core/java/android/app/GrammaticalInflectionManager.java
index bc6fe61..a55121a 100644
--- a/core/java/android/app/GrammaticalInflectionManager.java
+++ b/core/java/android/app/GrammaticalInflectionManager.java
@@ -100,7 +100,7 @@
 
     /**
      * Sets the current grammatical gender for all privileged applications. The value will be
-     * stored in an encrypted file at {@link android.os.Environment#getDataSystemCeDirectory(int)
+     * stored in an encrypted file at {@link android.os.Environment#getDataSystemCeDirectory(int)}
      *
      * @param grammaticalGender the terms of address the user preferred in system.
      *
@@ -121,8 +121,7 @@
     }
 
     /**
-     * Get the current grammatical gender of privileged application from the encrypted file,
-     * which is stored under {@link android.os.Environment#getDataSystemCeDirectory(int)}.
+     * Get the current grammatical gender of privileged application from the encrypted file.
      *
      * @return the value of grammatical gender
      *
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 93c2b5a..dd7db23 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -9195,6 +9195,12 @@
      * You can opt-out of this behavior by using {@link Notification.Builder#setColorized(boolean)}.
      * <p>
      *
+     * <p>
+     * Starting at {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM Android V} the
+     * {@link Notification#FLAG_NO_CLEAR NO_CLEAR flag} will be set for valid MediaStyle
+     * notifications.
+     * <p>
+     *
      * To use this style with your Notification, feed it to
      * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
      * <pre class="prettyprint">
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 7ee1332..15d692a 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -272,6 +272,10 @@
     private boolean mDemoted = false;
     private boolean mImportantConvo = false;
     private long mDeletedTime = DEFAULT_DELETION_TIME_MS;
+    /** Do not (de)serialize this value: it only affects logic in system_server and that logic
+     * is reset on each boot {@link NotificationAttentionHelper#buzzBeepBlinkLocked}.
+     */
+    private long mLastNotificationUpdateTimeMs = 0;
 
     /**
      * Creates a notification channel.
@@ -932,6 +936,23 @@
     }
 
     /**
+     * Returns the time of the notification post or last update for this channel.
+     * @return time of post / last update
+     * @hide
+     */
+    public long getLastNotificationUpdateTimeMs() {
+        return mLastNotificationUpdateTimeMs;
+    }
+
+    /**
+     * Sets the time of the notification post or last update for this channel.
+     * @hide
+     */
+    public void setLastNotificationUpdateTimeMs(long updateTimeMs) {
+        mLastNotificationUpdateTimeMs = updateTimeMs;
+    }
+
+    /**
      * @hide
      */
     public void populateFromXmlForRestore(XmlPullParser parser, boolean pkgInstalled,
@@ -1408,7 +1429,8 @@
                 + ", mParent=" + mParentId
                 + ", mConversationId=" + mConversationId
                 + ", mDemoted=" + mDemoted
-                + ", mImportantConvo=" + mImportantConvo;
+                + ", mImportantConvo=" + mImportantConvo
+                + ", mLastNotificationUpdateTimeMs=" + mLastNotificationUpdateTimeMs;
     }
 
     /** @hide */
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 79b68c1..b8bea9d 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -25,8 +25,12 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UserHandleAware;
 import android.annotation.WorkerThread;
 import android.app.Notification.Builder;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
@@ -1659,23 +1663,42 @@
     }
 
     /**
+     * For apps targeting {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and above, the
+     * {@code setNotificationListenerAccessGranted} method will use the user contained within the
+     * context.
+     * For apps targeting an SDK version <em>below</em> this, the user of the calling process will
+     * be used (Process.myUserHandle()).
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    public static final long SET_LISTENER_ACCESS_GRANTED_IS_USER_AWARE = 302563478L;
+
+    /**
      * Grants/revokes Notification Listener access to the given component for current user.
      * To grant access for a particular user, obtain this service by using the {@link Context}
      * provided by {@link Context#createPackageContextAsUser}
      *
      * @param listener Name of component to grant/revoke access
-     * @param granted Grant/revoke access
-     * @param userSet Whether the action was triggered explicitly by user
+     * @param granted  Grant/revoke access
+     * @param userSet  Whether the action was triggered explicitly by user
      * @hide
      */
     @SystemApi
     @TestApi
+    @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
     @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS)
     public void setNotificationListenerAccessGranted(
             @NonNull ComponentName listener, boolean granted, boolean userSet) {
         INotificationManager service = getService();
         try {
-            service.setNotificationListenerAccessGranted(listener, granted, userSet);
+            if (CompatChanges.isChangeEnabled(SET_LISTENER_ACCESS_GRANTED_IS_USER_AWARE)) {
+                service.setNotificationListenerAccessGrantedForUser(listener, mContext.getUserId(),
+                        granted, userSet);
+            } else {
+                service.setNotificationListenerAccessGranted(listener, granted, userSet);
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index 456c6af..7c69d37 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -1172,6 +1172,12 @@
             public static final String WORK_CATEGORY_HEADER = PREFIX + "WORK_CATEGORY_HEADER";
 
             /**
+             * Header for items under the private user
+             */
+            public static final String PRIVATE_CATEGORY_HEADER =
+                    PREFIX + "PRIVATE_CATEGORY_HEADER";
+
+            /**
              * Header for items under the personal user
              */
             public static final String PERSONAL_CATEGORY_HEADER =
@@ -1208,6 +1214,12 @@
             public static final String AUTO_SYNC_WORK_DATA = PREFIX + "AUTO_SYNC_WORK_DATA";
 
             /**
+             * Text for toggle to enable auto-sycing private data
+             */
+            public static final String AUTO_SYNC_PRIVATE_DATA = PREFIX
+                    + "AUTO_SYNC_PRIVATE_DATA";
+
+            /**
              * Summary for "More security settings" section when a work profile is on the device.
              */
             public static final String MORE_SECURITY_SETTINGS_WORK_PROFILE_SUMMARY = PREFIX
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 2fb428b..a84845a 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -240,6 +240,12 @@
     public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
 
     /**
+     * The length limit of Association tag.
+     * @hide
+     */
+    private static final int ASSOCIATION_TAG_LENGTH_LIMIT = 100;
+
+    /**
      * Callback for applications to receive updates about and the outcome of
      * {@link AssociationRequest} issued via {@code associate()} call.
      *
@@ -1409,7 +1415,7 @@
     /**
      * Sets the {@link AssociationInfo#getTag() tag} for this association.
      *
-     * <p>The length of the tag must be at most 20 characters.
+     * <p>The length of the tag must be at most 100 characters to save disk space.
      *
      * <p>This allows to store useful information about the associated devices.
      *
@@ -1421,8 +1427,8 @@
     public void setAssociationTag(int associationId, @NonNull String tag) {
         Objects.requireNonNull(tag, "tag cannot be null");
 
-        if (tag.length() > 20) {
-            throw new IllegalArgumentException("Length of the tag must be at most 20 characters");
+        if (tag.length() > ASSOCIATION_TAG_LENGTH_LIMIT) {
+            throw new IllegalArgumentException("Length of the tag must be at most 100 characters");
         }
 
         try {
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index ce883cd..0af4c92 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -113,6 +113,7 @@
      * <p class="note">This identifier may not be unique across virtual devices, in case there are
      * more than one virtual devices corresponding to the same physical device.
      */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
     public @Nullable String getPersistentDeviceId() {
         return mPersistentId;
     }
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index baed7f9..2569366 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -476,6 +476,7 @@
         /**
          * Returns the persistent ID of this virtual device.
          */
+        @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
         public @Nullable String getPersistentDeviceId() {
             return mVirtualDeviceInternal.getPersistentDeviceId();
         }
@@ -637,15 +638,15 @@
         /**
          * Specifies a component name to be exempt from the current activity launch policy.
          *
-         * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVIY} allows activity
-         * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT},
+         * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity
+         * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}),
          * then the specified component will be blocked from launching.
-         * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity
-         * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}, then
-         * the specified component will be allowed to launch.</p>
+         * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches
+         * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then the
+         * specified component will be allowed to launch.</p>
          *
-         * <p>Note that changing the activity launch policy will not affect current set of exempt
-         * components and it needs to be updated separately.</p>
+         * <p>Note that changing the activity launch policy will clear current set of exempt
+         * components.</p>
          *
          * @see #removeActivityPolicyExemption
          * @see #setDevicePolicy
@@ -660,15 +661,15 @@
         /**
          * Makes the specified component name to adhere to the default activity launch policy.
          *
-         * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVIY} allows activity
-         * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT},
+         * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity
+         * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}),
          * then the specified component will be allowed to launch.
-         * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity
-         * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}, then
-         * the specified component will be blocked from launching.</p>
+         * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches
+         * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then the
+         * specified component will be blocked from launching.</p>
          *
-         * <p>Note that changing the activity launch policy will not affect current set of exempt
-         * components and it needs to be updated separately.</p>
+         * <p>Note that changing the activity launch policy will clear current set of exempt
+         * components.</p>
          *
          * @see #addActivityPolicyExemption
          * @see #setDevicePolicy
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index d0e13cd..cf274f5 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -8,6 +8,14 @@
 }
 
 flag {
+  name: "enable_native_vdm"
+  namespace: "virtual_devices"
+  description: "Enable native VDM service"
+  bug: "303535376"
+  is_fixed_read_only: true
+}
+
+flag {
   name: "dynamic_policy"
   namespace: "virtual_devices"
   description: "Enable dynamic policy API"
diff --git a/core/java/android/companion/virtualnative/IVirtualDeviceManagerNative.aidl b/core/java/android/companion/virtualnative/IVirtualDeviceManagerNative.aidl
new file mode 100644
index 0000000..9f09d04
--- /dev/null
+++ b/core/java/android/companion/virtualnative/IVirtualDeviceManagerNative.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 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.companion.virtualnative;
+
+/**
+ * Parallel implementation of certain VirtualDeviceManager APIs that need to be exposed to native
+ * code.
+ *
+ * <p>These APIs are a parallel definition to the APIs in VirtualDeviceManager and/or
+ * VirtualDeviceManagerInternal, so they can technically diverge. However, it's good practice to
+ * keep these APIs in sync with each other.</p>
+ *
+ * <p>Even though the name implies otherwise, the implementation is actually in Java. The 'native'
+ * suffix comes from the intended usage - native framework backends that need to communicate with
+ * VDM for some reason.</p>
+ *
+ * <p>Because these APIs are exposed to native code that runs in the app process, they may be
+ * accessed by apps directly, even though they're hidden. Care should be taken to avoid exposing
+ * sensitive data or potential security holes.</p>
+ *
+ * @hide
+ */
+interface IVirtualDeviceManagerNative {
+    /**
+     * Counterpart to VirtualDeviceParams#DevicePolicy.
+     */
+    const int DEVICE_POLICY_DEFAULT = 0;
+    const int DEVICE_POLICY_CUSTOM = 1;
+
+    /**
+     * Counterpart to VirtualDeviceParams#PolicyType.
+     */
+    const int POLICY_TYPE_SENSORS = 0;
+    const int POLICY_TYPE_AUDIO = 1;
+    const int POLICY_TYPE_RECENTS = 2;
+    const int POLICY_TYPE_ACTIVITY = 3;
+
+    /**
+     * Returns the IDs for all VirtualDevices where an app with the given is running.
+     *
+     * Note that this returns only VirtualDevice IDs: if the app is not running on any virtual
+     * device, then an an empty array is returned. This does not include information about whether
+     * the app is running on the default device or not.
+     */
+    int[] getDeviceIdsForUid(int uid);
+
+    /**
+     * Returns the device policy for the given virtual device and policy type.
+     */
+    int getDevicePolicy(int deviceId, int policyType);
+}
\ No newline at end of file
diff --git a/core/java/android/companion/virtualnative/OWNERS b/core/java/android/companion/virtualnative/OWNERS
new file mode 100644
index 0000000..2968104
--- /dev/null
+++ b/core/java/android/companion/virtualnative/OWNERS
@@ -0,0 +1 @@
+include /services/companion/java/com/android/server/companion/virtual/OWNERS
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 15678a7..bfc1eec 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -31,6 +32,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.permission.PermissionManager;
+import android.permission.flags.Flags;
 import android.util.ArraySet;
 
 import com.android.internal.annotations.Immutable;
@@ -163,6 +165,7 @@
 
     /** @hide */
     @TestApi
+    @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)
     public AttributionSource(int uid, int pid, @Nullable String packageName,
             @Nullable String attributionTag, @NonNull IBinder token,
             @Nullable String[] renouncedPermissions,
@@ -528,6 +531,7 @@
      * <p>
      * This device ID is used for permissions checking during attribution source validation.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)
     public int getDeviceId() {
         return mAttributionSourceState.deviceId;
     }
@@ -715,6 +719,7 @@
          *
          * @return the builder
          */
+        @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)
         public @NonNull Builder setDeviceId(int deviceId) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x12;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 44a9acd..5f4c05f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2790,6 +2790,20 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
+
+    /**
+     * Broadcast Action: An application package that was previously in the stopped state has been
+     * started and is no longer considered stopped.
+     * <ul>
+     * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
+     * </ul>
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED)
+    public static final String ACTION_PACKAGE_UNSTOPPED = "android.intent.action.PACKAGE_UNSTOPPED";
+
     /**
      * Broadcast Action: Sent to the system rollback manager when a package
      * needs to have rollback enabled.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index aca88d6..9926415 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -308,6 +308,8 @@
 
     boolean isPackageQuarantinedForUser(String packageName, int userId);
 
+    boolean isPackageStoppedForUser(String packageName, int userId);
+
     Bundle getSuspendedPackageAppExtras(String packageName, int userId);
 
     /**
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3a9e9bf..673a8a5 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -371,13 +371,6 @@
             "android.content.pm.extra.UNARCHIVE_ALL_USERS";
 
     /**
-     * A list of warnings that occurred during installation.
-     *
-     * @hide
-     */
-    public static final String EXTRA_WARNINGS = "android.content.pm.extra.WARNINGS";
-
-    /**
      * Streaming installation pending.
      * Caller should make sure DataLoader is able to prepare image and reinitiate the operation.
      *
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3fc515d..45338bb 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4802,6 +4802,7 @@
      * @hide
      */
     @SystemApi
+    @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)
     public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID =
             "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID";
 
@@ -9877,6 +9878,18 @@
     }
 
     /**
+     * Query if an app is currently stopped.
+     *
+     * @return {@code true} if the given package is stopped, {@code false} otherwise
+     * @throws NameNotFoundException if the package could not be found.
+     * @see ApplicationInfo#FLAG_STOPPED
+     */
+    @FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED)
+    public boolean isPackageStopped(@NonNull String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException("isPackageStopped not implemented");
+    }
+
+    /**
      * Query if an app is currently quarantined.
      *
      * @return {@code true} if the given package is quarantined, {@code false} otherwise
@@ -9887,7 +9900,6 @@
     public boolean isPackageQuarantined(@NonNull String packageName) throws NameNotFoundException {
         throw new UnsupportedOperationException("isPackageQuarantined not implemented");
     }
-
     /**
      * Provide a hint of what the {@link ApplicationInfo#category} value should
      * be for the given package.
diff --git a/core/java/android/content/pm/Signature.aidl b/core/java/android/content/pm/Signature.aidl
deleted file mode 100644
index 36c127a..0000000
--- a/core/java/android/content/pm/Signature.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/* //device/java/android/android/view/WindowManager.aidl
-**
-** Copyright 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 android.content.pm;
-
-/* For the key attestation application id provider service we needed a native implementation
- * of the Signature parcelable because the service is used by the native keystore.
- * The native implementation is now located at
- * system/security/keystore/Signature.cpp
- * and
- * system/security/keystore/include/keystore/Signature.h.
- * and can be used by linking against libkeystore_binder.
- *
- * This is not the best arrangement. If you, dear reader, happen to implement native implementations
- * for the package manager's parcelables, consider moving Signature.cpp/.h to your library and
- * adjust keystore's dependencies accordingly. Thank you.
- */
-parcelable Signature cpp_header "keystore/Signature.h";
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index 96af2b6..884d463 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -49,6 +49,7 @@
     private static final String ATTR_SHOW_IN_LAUNCHER = "showInLauncher";
     private static final String ATTR_START_WITH_PARENT = "startWithParent";
     private static final String ATTR_SHOW_IN_SETTINGS = "showInSettings";
+    private static final String ATTR_HIDE_IN_SETTINGS_IN_QUIET_MODE = "hideInSettingsInQuietMode";
     private static final String ATTR_INHERIT_DEVICE_POLICY = "inheritDevicePolicy";
     private static final String ATTR_USE_PARENTS_CONTACTS = "useParentsContacts";
     private static final String ATTR_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA =
@@ -78,6 +79,7 @@
             INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT,
             INDEX_DELETE_APP_WITH_PARENT,
             INDEX_ALWAYS_VISIBLE,
+            INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE,
     })
     @Retention(RetentionPolicy.SOURCE)
     private @interface PropertyIndex {
@@ -94,6 +96,7 @@
     private static final int INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT = 9;
     private static final int INDEX_DELETE_APP_WITH_PARENT = 10;
     private static final int INDEX_ALWAYS_VISIBLE = 11;
+    private static final int INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE = 12;
     /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
     private long mPropertiesPresent = 0;
 
@@ -324,6 +327,7 @@
         if (hasManagePermission) {
             // Add items that require MANAGE_USERS or stronger.
             setShowInSettings(orig.getShowInSettings());
+            setHideInSettingsInQuietMode(orig.getHideInSettingsInQuietMode());
             setUseParentsContacts(orig.getUseParentsContacts());
         }
         if (hasQueryOrManagePermission) {
@@ -409,6 +413,42 @@
     private @ShowInSettings int mShowInSettings;
 
     /**
+     * Returns whether a user should be shown in the Settings app depending on the quiet mode.
+     * This is generally inapplicable for non-profile users.
+     *
+     * <p> {@link #getShowInSettings()} returns whether / how a user should be shown in Settings.
+     * However, if this behaviour should be changed based on the quiet mode of the user, then this
+     * property can be used. If the property is not set then the user is shown in the Settings app
+     * irrespective of whether the user is in quiet mode or not. If the property is set, then the
+     * user is shown in the Settings app only if the user is not in the quiet mode. Please note that
+     * this property takes effect only if {@link #getShowInSettings()} does not return
+     * {@link #SHOW_IN_SETTINGS_NO}.
+     *
+     * <p> The caller must have {@link android.Manifest.permission#MANAGE_USERS} to query this
+     * property.
+     *
+     * @return true if a profile should be shown in the Settings only when the user is not in the
+     * quiet mode.
+     *
+     * See also {@link #getShowInSettings()}, {@link #setShowInSettings(int)},
+     * {@link ShowInSettings}
+     *
+     * @hide
+     */
+    public boolean getHideInSettingsInQuietMode() {
+        if (isPresent(INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE)) return mHideInSettingsInQuietMode;
+        if (mDefaultProperties != null) return mDefaultProperties.mHideInSettingsInQuietMode;
+        throw new SecurityException(
+                "You don't have permission to query HideInSettingsInQuietMode");
+    }
+    /** @hide */
+    public void setHideInSettingsInQuietMode(boolean hideInSettingsInQuietMode) {
+        this.mHideInSettingsInQuietMode = hideInSettingsInQuietMode;
+        setPresent(INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE);
+    }
+    private boolean mHideInSettingsInQuietMode;
+
+    /**
      * Returns whether a profile should be started when its parent starts (unless in quiet mode).
      * This only applies for users that have parents (i.e. for profiles).
      * @hide
@@ -724,6 +764,9 @@
                 case ATTR_SHOW_IN_SETTINGS:
                     setShowInSettings(parser.getAttributeInt(i));
                     break;
+                case ATTR_HIDE_IN_SETTINGS_IN_QUIET_MODE:
+                    setHideInSettingsInQuietMode(parser.getAttributeBoolean(i));
+                    break;
                 case ATTR_INHERIT_DEVICE_POLICY:
                     setInheritDevicePolicy(parser.getAttributeInt(i));
                     break;
@@ -777,6 +820,10 @@
         if (isPresent(INDEX_SHOW_IN_SETTINGS)) {
             serializer.attributeInt(null, ATTR_SHOW_IN_SETTINGS, mShowInSettings);
         }
+        if (isPresent(INDEX_HIDE_IN_SETTINGS_IN_QUIET_MODE)) {
+            serializer.attributeBoolean(null, ATTR_HIDE_IN_SETTINGS_IN_QUIET_MODE,
+                    mHideInSettingsInQuietMode);
+        }
         if (isPresent(INDEX_INHERIT_DEVICE_POLICY)) {
             serializer.attributeInt(null, ATTR_INHERIT_DEVICE_POLICY,
                     mInheritDevicePolicy);
@@ -823,6 +870,7 @@
         dest.writeInt(mShowInLauncher);
         dest.writeBoolean(mStartWithParent);
         dest.writeInt(mShowInSettings);
+        dest.writeBoolean(mHideInSettingsInQuietMode);
         dest.writeInt(mInheritDevicePolicy);
         dest.writeBoolean(mUseParentsContacts);
         dest.writeBoolean(mUpdateCrossProfileIntentFiltersOnOTA);
@@ -845,6 +893,7 @@
         mShowInLauncher = source.readInt();
         mStartWithParent = source.readBoolean();
         mShowInSettings = source.readInt();
+        mHideInSettingsInQuietMode = source.readBoolean();
         mInheritDevicePolicy = source.readInt();
         mUseParentsContacts = source.readBoolean();
         mUpdateCrossProfileIntentFiltersOnOTA = source.readBoolean();
@@ -881,6 +930,7 @@
         private @ShowInLauncher int mShowInLauncher = SHOW_IN_LAUNCHER_WITH_PARENT;
         private boolean mStartWithParent = false;
         private @ShowInSettings int mShowInSettings = SHOW_IN_SETTINGS_WITH_PARENT;
+        private boolean mHideInSettingsInQuietMode = false;
         private @InheritDevicePolicy int mInheritDevicePolicy = INHERIT_DEVICE_POLICY_NO;
         private boolean mUseParentsContacts = false;
         private boolean mUpdateCrossProfileIntentFiltersOnOTA = false;
@@ -910,6 +960,12 @@
             return this;
         }
 
+        /** Sets the value for {@link #mHideInSettingsInQuietMode} */
+        public Builder setHideInSettingsInQuietMode(boolean hideInSettingsInQuietMode) {
+            mHideInSettingsInQuietMode = hideInSettingsInQuietMode;
+            return this;
+        }
+
         /** Sets the value for {@link #mInheritDevicePolicy}*/
         public Builder setInheritDevicePolicy(
                 @InheritDevicePolicy int inheritRestrictionsDevicePolicy) {
@@ -972,6 +1028,7 @@
                     mShowInLauncher,
                     mStartWithParent,
                     mShowInSettings,
+                    mHideInSettingsInQuietMode,
                     mInheritDevicePolicy,
                     mUseParentsContacts,
                     mUpdateCrossProfileIntentFiltersOnOTA,
@@ -989,6 +1046,7 @@
             @ShowInLauncher int showInLauncher,
             boolean startWithParent,
             @ShowInSettings int showInSettings,
+            boolean hideInSettingsInQuietMode,
             @InheritDevicePolicy int inheritDevicePolicy,
             boolean useParentsContacts, boolean updateCrossProfileIntentFiltersOnOTA,
             @CrossProfileIntentFilterAccessControlLevel int crossProfileIntentFilterAccessControl,
@@ -1001,6 +1059,7 @@
         setShowInLauncher(showInLauncher);
         setStartWithParent(startWithParent);
         setShowInSettings(showInSettings);
+        setHideInSettingsInQuietMode(hideInSettingsInQuietMode);
         setInheritDevicePolicy(inheritDevicePolicy);
         setUseParentsContacts(useParentsContacts);
         setUpdateCrossProfileIntentFiltersOnOTA(updateCrossProfileIntentFiltersOnOTA);
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 89ca915..ff21bfb 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -19,6 +19,7 @@
     namespace: "package_manager_service"
     description: "Feature flag to enable the prevent sdk-library be an application."
     bug: "295843617"
+    is_fixed_read_only: true
 }
 
 flag {
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index ea0f049..3ec239c 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -8,8 +8,23 @@
 }
 
 flag {
+    name: "save_global_and_guest_restrictions_on_system_user_xml_read_only"
+    namespace: "multiuser"
+    description: "Save guest and device policy global restrictions on the SYSTEM user's XML file. (Read only flag)"
+    bug: "301067944"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "bind_wallpaper_service_on_its_own_thread_during_a_user_switch"
     namespace: "multiuser"
     description: "Bind wallpaper service on its own thread instead of system_server's main handler during a user switch."
     bug: "302100344"
 }
+
+flag {
+    name: "support_communal_profile"
+    namespace: "multiuser"
+    description: "Framework support for communal profile."
+    bug: "285426179"
+}
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java
index 231e4bc..1b130a9 100644
--- a/core/java/android/credentials/GetCandidateCredentialsResponse.java
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java
@@ -53,6 +53,15 @@
         mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList);
     }
 
+    /**
+     * Returns candidate provider data list.
+     *
+     * @hide
+     */
+    public List<GetCredentialProviderData> getCandidateProviderDataList() {
+        return mCandidateProviderDataList;
+    }
+
     protected GetCandidateCredentialsResponse(Parcel in) {
         List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>();
         in.readTypedList(candidateProviderDataList, GetCredentialProviderData.CREATOR);
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index 0d0305b..9b819a7 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -5,4 +5,11 @@
     name: "settings_activity_enabled"
     description: "Enable the Credential Manager Settings Activity APIs"
     bug: "300014059"
-}
\ No newline at end of file
+}
+
+flag {
+    namespace: "credential_manager"
+    name: "instant_apps_enabled"
+    description: "Enables Credential Manager to work with Instant Apps"
+    bug: "302190269"
+}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index af448f0..490ff64 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -20,8 +20,10 @@
 import static android.Manifest.permission.USE_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.hardware.biometrics.BiometricManager.Authenticators;
+import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -53,6 +55,7 @@
 import java.util.concurrent.Executor;
 
 import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
 import javax.crypto.Mac;
 
 /**
@@ -748,7 +751,7 @@
      * A wrapper class for the cryptographic operations supported by BiometricPrompt.
      *
      * <p>Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac},
-     * {@link IdentityCredential}, and {@link PresentationSession}.
+     * {@link IdentityCredential}, {@link PresentationSession} and {@link KeyAgreement}.
      *
      * <p>Cryptographic operations in Android can be split into two categories: auth-per-use and
      * time-based. This is specified during key creation via the timeout parameter of the
@@ -793,6 +796,11 @@
             super(session);
         }
 
+        @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT)
+        public CryptoObject(@NonNull KeyAgreement keyAgreement) {
+            super(keyAgreement);
+        }
+
         /**
          * Get {@link Signature} object.
          * @return {@link Signature} object or null if this doesn't contain one.
@@ -834,6 +842,15 @@
         public @Nullable PresentationSession getPresentationSession() {
             return super.getPresentationSession();
         }
+
+        /**
+         * Get {@link KeyAgreement} object.
+         * @return {@link KeyAgreement} object or null if this doesn't contain one.
+         */
+        @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT)
+        public @Nullable KeyAgreement getKeyAgreement() {
+            return super.getKeyAgreement();
+        }
     }
 
     /**
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
index 267ef36..6ac1efb 100644
--- a/core/java/android/hardware/biometrics/CryptoObject.java
+++ b/core/java/android/hardware/biometrics/CryptoObject.java
@@ -16,6 +16,9 @@
 
 package android.hardware.biometrics;
 
+import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.security.identity.IdentityCredential;
 import android.security.identity.PresentationSession;
@@ -24,6 +27,7 @@
 import java.security.Signature;
 
 import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
 import javax.crypto.Mac;
 
 /**
@@ -62,6 +66,11 @@
         mCrypto = session;
     }
 
+    @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT)
+    public CryptoObject(@NonNull KeyAgreement keyAgreement) {
+        mCrypto = keyAgreement;
+    }
+
     /**
      * Get {@link Signature} object.
      * @return {@link Signature} object or null if this doesn't contain one.
@@ -105,6 +114,15 @@
     }
 
     /**
+     * Get {@link KeyAgreement} object.
+     * @return {@link KeyAgreement} object or null if this doesn't contain one.
+     */
+    @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT)
+    public KeyAgreement getKeyAgreement() {
+        return mCrypto instanceof KeyAgreement ? (KeyAgreement) mCrypto : null;
+    }
+
+    /**
      * @hide
      * @return the opId associated with this object or 0 if none
      */
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 990ebc5..f347909 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -20,6 +20,7 @@
 import static android.view.Display.HdrCapabilities.HdrType;
 
 import android.Manifest;
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -27,7 +28,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -377,7 +377,7 @@
      * @see #createVirtualDisplay
      * @hide
      */
-    @SuppressLint("UnflaggedApi")
+    @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS)
     @SystemApi
     public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
 
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index f594377..5bfda70 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -24,12 +24,14 @@
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.Manifest.permission.USE_FINGERPRINT;
 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE;
+import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT;
 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
 
 import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE;
 import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_HAS_ENROLLED_FINGERPRINTS;
 import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_IS_HARDWARE_DETECTED;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -76,6 +78,7 @@
 import java.util.concurrent.Executor;
 
 import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
 import javax.crypto.Mac;
 
 /**
@@ -312,6 +315,16 @@
         public PresentationSession getPresentationSession() {
             return super.getPresentationSession();
         }
+
+        /**
+         * Get {@link KeyAgreement} object.
+         * @return {@link KeyAgreement} object or null if this doesn't contain one.
+         * @hide
+         */
+        @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT)
+        public KeyAgreement getKeyAgreement() {
+            return super.getKeyAgreement();
+        }
     }
 
     /**
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
index bbfed24..883f157 100644
--- a/core/java/android/hardware/input/KeyboardLayout.java
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -82,8 +82,8 @@
         DVORAK(4, LAYOUT_TYPE_DVORAK),
         COLEMAK(5, LAYOUT_TYPE_COLEMAK),
         WORKMAN(6, LAYOUT_TYPE_WORKMAN),
-        TURKISH_F(7, LAYOUT_TYPE_TURKISH_F),
-        TURKISH_Q(8, LAYOUT_TYPE_TURKISH_Q),
+        TURKISH_Q(7, LAYOUT_TYPE_TURKISH_Q),
+        TURKISH_F(8, LAYOUT_TYPE_TURKISH_F),
         EXTENDED(9, LAYOUT_TYPE_EXTENDED);
 
         private final int mValue;
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index a6d8caf..0c95c2e 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -79,4 +79,9 @@
     Map getTagIntentAppPreferenceForUser(int userId);
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
     int setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow);
+
+    boolean isReaderOptionEnabled();
+    boolean isReaderOptionSupported();
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
+    boolean enableReaderOption(boolean enable);
 }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index a9eb672..4658630 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -17,6 +17,7 @@
 package android.nfc;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -484,7 +485,6 @@
     /**
      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
      * to another device.
-     * @see #setOnNdefPushCompleteCallback
      * @deprecated this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
@@ -496,7 +496,6 @@
          * <p>This callback is usually made on a binder thread (not the UI thread).
          *
          * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
-         * @see #setNdefPushMessageCallback
          */
         public void onNdefPushComplete(NfcEvent event);
     }
@@ -504,11 +503,11 @@
     /**
      * A callback to be invoked when another NFC device capable of NDEF push (Android Beam)
      * is within range.
-     * <p>Implement this interface and pass it to {@link
+     * <p>Implement this interface and pass it to {@code
      * NfcAdapter#setNdefPushMessageCallback setNdefPushMessageCallback()} in order to create an
      * {@link NdefMessage} at the moment that another device is within range for NFC. Using this
      * callback allows you to create a message with data that might vary based on the
-     * content currently visible to the user. Alternatively, you can call {@link
+     * content currently visible to the user. Alternatively, you can call {@code
      * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
      * same data.
      * @deprecated this feature is removed. File sharing can work using other technology like
@@ -1828,6 +1827,97 @@
     }
 
     /**
+     * Sets NFC Reader option feature.
+     * <p>This API is for the Settings application.
+     * @return True if successful
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean enableReaderOption(boolean enable) {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.enableReaderOption(enable);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.enableReaderOption(enable);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Checks if the device supports NFC Reader option functionality.
+     *
+     * @return True if device supports NFC Reader option, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
+    public boolean isReaderOptionSupported() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.isReaderOptionSupported();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.isReaderOptionSupported();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Checks NFC Reader option feature is enabled.
+     *
+     * @return True if NFC Reader option  is enabled, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @throws UnsupportedOperationException if device doesn't support
+     *         NFC Reader option functionality. {@link #isReaderOptionSupported}
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
+    public boolean isReaderOptionEnabled() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.isReaderOptionEnabled();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.isReaderOptionEnabled();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
      * Enable NDEF Push feature.
      * <p>This API is for the Settings application.
      * @hide
diff --git a/core/java/android/nfc/flags.aconfig b/core/java/android/nfc/flags.aconfig
index e3faf39..55b0b42 100644
--- a/core/java/android/nfc/flags.aconfig
+++ b/core/java/android/nfc/flags.aconfig
@@ -6,3 +6,10 @@
     description: "Flag for NFC mainline changes"
     bug: "292140387"
 }
+
+flag {
+    name: "enable_nfc_reader_option"
+    namespace: "nfc"
+    description: "Flag for NFC reader option API changes"
+    bug: "291187960"
+}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 092923e..6a4ec9b 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -16,7 +16,10 @@
 
 package android.os;
 
+import static android.os.Flags.FLAG_STATE_OF_HEALTH_PUBLIC;
+
 import android.Manifest.permission;
+import android.annotation.FlaggedApi;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -354,17 +357,11 @@
     public static final int BATTERY_PROPERTY_CHARGING_POLICY = 9;
 
     /**
-     *
-     * Percentage representing the measured battery state of health (remaining
-     * estimated full charge capacity relative to the rated capacity in %).
-     *
-     * <p class="note">
-     * The sender must hold the {@link android.Manifest.permission#BATTERY_STATS} permission.
-     *
-     * @hide
+     * Percentage representing the measured battery state of health.
+     * This is the remaining estimated full charge capacity relative
+     * to the rated capacity in %.
      */
-    @RequiresPermission(permission.BATTERY_STATS)
-    @SystemApi
+    @FlaggedApi(FLAG_STATE_OF_HEALTH_PUBLIC)
     public static final int BATTERY_PROPERTY_STATE_OF_HEALTH = 10;
 
     private final Context mContext;
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 955fad3..3abe9a0 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -520,8 +520,9 @@
      * @param uid calling package uid
      * @param reason why Bluetooth has been turned on
      * @param packageName package responsible for this change
-     * @Deprecated Bluetooth self report its state and no longer call this
+     * @deprecated Bluetooth self report its state and no longer call this
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
     public void reportBluetoothOn(int uid, int reason, @NonNull String packageName) {
     }
@@ -532,8 +533,9 @@
      * @param uid calling package uid
      * @param reason why Bluetooth has been turned on
      * @param packageName package responsible for this change
-     * @Deprecated Bluetooth self report its state and no longer call this
+     * @deprecated Bluetooth self report its state and no longer call this
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
     public void reportBluetoothOff(int uid, int reason, @NonNull String packageName) {
     }
diff --git a/core/java/android/os/OomKillRecord.java b/core/java/android/os/OomKillRecord.java
new file mode 100644
index 0000000..151a65f
--- /dev/null
+++ b/core/java/android/os/OomKillRecord.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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.os;
+
+
+/**
+ * Expected data to get back from the OOM event's file.
+ * Note that this should be equivalent to the struct <b>OomKill</b> inside
+ * <pre>
+ * system/memory/libmeminfo/libmemevents/include/memevents.h
+ * </pre>
+ *
+ * @hide
+ */
+public final class OomKillRecord {
+    private long mTimeStampInMillis;
+    private int mPid;
+    private int mUid;
+    private String mProcessName;
+    private short mOomScoreAdj;
+
+    public OomKillRecord(long timeStampInMillis, int pid, int uid,
+                            String processName, short oomScoreAdj) {
+        this.mTimeStampInMillis = timeStampInMillis;
+        this.mPid = pid;
+        this.mUid = uid;
+        this.mProcessName = processName;
+        this.mOomScoreAdj = oomScoreAdj;
+    }
+
+    public long getTimestampMilli() {
+        return mTimeStampInMillis;
+    }
+
+    public int getPid() {
+        return mPid;
+    }
+
+    public int getUid() {
+        return mUid;
+    }
+
+    public String getProcessName() {
+        return mProcessName;
+    }
+
+    public short getOomScoreAdj() {
+        return mOomScoreAdj;
+    }
+}
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index a95e66d..37559b3 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -1,6 +1,13 @@
 package: "android.os"
 
 flag {
+    name: "state_of_health_public"
+    namespace: "system_sw_battery"
+    description: "Feature flag for making state_of_health a public api."
+    bug: "288842045"
+}
+
+flag {
     name: "disallow_cellular_null_ciphers_restriction"
     namespace: "cellular_security"
     description: "Guards a new UserManager user restriction that admins can use to require cellular encryption on their managed devices."
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index c01ef3d..88f62f3 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -12,4 +12,18 @@
     name: "haptics_customization_enabled"
     description: "Enables the haptics customization feature"
     bug: "241918098"
-}
\ No newline at end of file
+}
+
+flag {
+    namespace: "haptics"
+    name: "haptics_customization_ringtone_v2_enabled"
+    description: "Enables the usage of the new RingtoneV2 class"
+    bug: "241918098"
+}
+
+flag {
+    namespace: "haptics"
+    name: "enable_vibration_serialization_apis"
+    description: "Enables the APIs for vibration serialization/deserialization."
+    bug: "245129509"
+}
diff --git a/core/java/android/os/vibrator/persistence/ParsedVibration.java b/core/java/android/os/vibrator/persistence/ParsedVibration.java
index ded74ea..3d1deea 100644
--- a/core/java/android/os/vibrator/persistence/ParsedVibration.java
+++ b/core/java/android/os/vibrator/persistence/ParsedVibration.java
@@ -16,6 +16,7 @@
 
 package android.os.vibrator.persistence;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -34,6 +35,7 @@
  *
  * @hide
  */
+@FlaggedApi(android.os.vibrator.Flags.FLAG_ENABLE_VIBRATION_SERIALIZATION_APIS)
 @TestApi
 public class ParsedVibration {
     private final List<VibrationEffect> mEffects;
diff --git a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
index e08cc42..fed1053 100644
--- a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
+++ b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
@@ -16,6 +16,7 @@
 
 package android.os.vibrator.persistence;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -115,6 +116,7 @@
  *
  * @hide
  */
+@FlaggedApi(android.os.vibrator.Flags.FLAG_ENABLE_VIBRATION_SERIALIZATION_APIS)
 @TestApi
 public final class VibrationXmlParser {
     private static final String TAG = "VibrationXmlParser";
diff --git a/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java b/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java
index 1cdfa4f..2880454 100644
--- a/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java
+++ b/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java
@@ -16,6 +16,7 @@
 
 package android.os.vibrator.persistence;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
@@ -42,6 +43,7 @@
  *
  * @hide
  */
+@FlaggedApi(android.os.vibrator.Flags.FLAG_ENABLE_VIBRATION_SERIALIZATION_APIS)
 @TestApi
 public final class VibrationXmlSerializer {
 
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 5626b94..d8534dd 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "device_aware_permission_apis"
+  is_fixed_read_only: true
   namespace: "permissions"
   description: "enable device aware permission APIs"
   bug: "274852670"
@@ -19,4 +20,4 @@
     namespace: "permissions"
     description: "enable role controller in system server"
     bug: "302562590"
-}
\ No newline at end of file
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d09f0a8..b19a034 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4866,7 +4866,8 @@
                 "display_color_mode_vendor_hint";
 
         /**
-         * The user selected min refresh rate in frames per second.
+         * The user selected min refresh rate in frames per second. If infinite, the user wants
+         * the highest possible refresh rate.
          *
          * If this isn't set, 0 will be used.
          * @hide
@@ -4875,7 +4876,8 @@
         public static final String MIN_REFRESH_RATE = "min_refresh_rate";
 
         /**
-         * The user selected peak refresh rate in frames per second.
+         * The user selected peak refresh rate in frames per second. If infinite, the user wants
+         * the highest possible refresh rate.
          *
          * If this isn't set, the system falls back to a device specific default.
          * @hide
@@ -5352,6 +5354,37 @@
         public static final Uri NOTIFICATION_SOUND_CACHE_URI = getUriFor(NOTIFICATION_SOUND_CACHE);
 
         /**
+         * When enabled, notifications attention effects: sound, vibration, flashing
+         * will have a cooldown timer.
+         *
+         * The value 1 - enable, 0 - disable
+         * @hide
+         */
+        public static final String NOTIFICATION_COOLDOWN_ENABLED =
+            "notification_cooldown_enabled";
+
+        /**
+         * When enabled, notification cooldown will apply to all notifications.
+         * Otherwise cooldown will only apply to conversations.
+         *
+         * The value 1 - enable, 0 - disable
+         * Only valid if {@code NOTIFICATION_COOLDOWN_ENABLED} is enabled.
+         * @hide
+         */
+        public static final String NOTIFICATION_COOLDOWN_ALL =
+            "notification_cooldown_all";
+
+        /**
+         * When enabled, notification attention effects will be restricted to vibration only
+         * as long as the screen is unlocked.
+         *
+         * The value 1 - enable, 0 - disable
+         * @hide
+         */
+        public static final String NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED =
+            "notification_cooldown_vibrate_unlocked";
+
+        /**
          * Persistent store for the system-wide default alarm alert.
          *
          * @see #RINGTONE
@@ -5664,6 +5697,37 @@
         public static final String SHOW_ROTARY_INPUT = "show_rotary_input";
 
         /**
+         * The screen backlight brightness for automatic mode.
+         *
+         * <p>Value should be one of:
+         *      <ul>
+         *        <li>SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT
+         *        <li>SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL
+         *        <li>SCREEN_BRIGHTNESS_AUTOMATIC_DIM
+         *      </ul>
+         * @hide
+         */
+        public static final String SCREEN_BRIGHTNESS_FOR_ALS = "screen_brightness_for_als";
+
+        /**
+         * SCREEN_BRIGHTNESS_FOR_ALS value for automatic bright.
+         * @hide
+         */
+        public static final int SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT = 1;
+
+        /**
+         * SCREEN_BRIGHTNESS_FOR_ALS value for automatic normal.
+         * @hide
+         */
+        public static final int SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL = 2;
+
+        /**
+         * SCREEN_BRIGHTNESS_FOR_ALS value for automatic dim.
+         * @hide
+         */
+        public static final int SCREEN_BRIGHTNESS_AUTOMATIC_DIM = 3;
+
+        /**
          * Log raw orientation data from
          * {@link com.android.server.policy.WindowOrientationListener} for use with the
          * orientationplot.py tool.
@@ -11147,6 +11211,12 @@
         public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving";
 
         /**
+         * Volume dialog timeout in ms.
+         * @hide
+         */
+        public static final String VOLUME_DIALOG_DISMISS_TIMEOUT = "volume_dialog_dismiss_timeout";
+
+        /**
          * What behavior should be invoked when the volume hush gesture is triggered
          * One of VOLUME_HUSH_OFF, VOLUME_HUSH_VIBRATE, VOLUME_HUSH_MUTE.
          *
@@ -11576,6 +11646,45 @@
                 "accessibility_magnification_joystick_enabled";
 
         /**
+         * Controls magnification enable gesture. Accessibility magnification can have one or more
+         * enable gestures.
+         *
+         * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE
+         * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP
+         * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP
+         * @hide
+         */
+        public static final String ACCESSIBILITY_MAGNIFICATION_GESTURE =
+                "accessibility_magnification_gesture";
+
+        /**
+         * Magnification enable gesture value that is a default value.
+         * @hide
+         */
+        public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE = 0x0;
+
+        /**
+         * Magnification enable gesture value is single finger triple tap.
+         * @hide
+         */
+        public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP = 0x1;
+
+        /**
+         * Magnification enable gesture value is two finger triple tap.
+         * @hide
+         */
+        public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP = 0x2;
+
+        /**
+         * Magnification enable gesture values include single finger triple tap and two finger
+         * triple tap.
+         * @hide
+         */
+        public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_ALL =
+                ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP
+                | ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP;
+
+        /**
          * Controls magnification capability. Accessibility magnification is capable of at least one
          * of the magnification modes.
          *
@@ -12393,6 +12502,13 @@
                 "wireless_charging_started_sound";
 
         /**
+         * Whether to auto enable reverse charging once plugged-in.
+         * @hide
+         */
+        public static final String REVERSE_CHARGING_AUTO_ON =
+                "settings_key_reverse_charging_auto_turn_on";
+
+        /**
          * URI for "wired charging started" sound.
          * @hide
          */
diff --git a/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl b/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl
deleted file mode 100644
index dbffd5f..0000000
--- a/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl
+++ /dev/null
@@ -1,32 +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.security.keymaster;
-
-import android.security.keymaster.KeyAttestationApplicationId;
-import android.security.keymaster.KeyAttestationPackageInfo;
-import android.content.pm.Signature;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IKeyAttestationApplicationIdProvider {
-    /* keep in sync with /system/security/keystore/keystore_attestation_id.cpp */
-    KeyAttestationApplicationId getKeyAttestationApplicationId(int uid);
-}
diff --git a/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl b/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl
deleted file mode 100644
index 9f6ff58..0000000
--- a/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl
+++ /dev/null
@@ -1,22 +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.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationApplicationId cpp_header "keystore/KeyAttestationApplicationId.h";
diff --git a/core/java/android/security/keymaster/KeyAttestationApplicationId.java b/core/java/android/security/keymaster/KeyAttestationApplicationId.java
deleted file mode 100644
index 670f30e1b..0000000
--- a/core/java/android/security/keymaster/KeyAttestationApplicationId.java
+++ /dev/null
@@ -1,74 +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.security.keymaster;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * @hide
- * The information aggregated by this class is used by keystore to identify a caller of the
- * keystore API toward a remote party. It aggregates multiple PackageInfos because keystore
- * can only determine a caller by uid granularity, and a uid can be shared by multiple packages.
- * The remote party must decide if it trusts all of the packages enough to consider the
- * confidentiality of the key material in question intact.
- */
-public class KeyAttestationApplicationId implements Parcelable {
-    private final KeyAttestationPackageInfo[] mAttestationPackageInfos;
-
-    /**
-     * @param mAttestationPackageInfos
-     */
-    public KeyAttestationApplicationId(KeyAttestationPackageInfo[] mAttestationPackageInfos) {
-        super();
-        this.mAttestationPackageInfos = mAttestationPackageInfos;
-    }
-
-    /**
-     * @return the mAttestationPackageInfos
-     */
-    public KeyAttestationPackageInfo[] getAttestationPackageInfos() {
-        return mAttestationPackageInfos;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeTypedArray(mAttestationPackageInfos, flags);
-    }
-
-    public static final @android.annotation.NonNull Parcelable.Creator<KeyAttestationApplicationId> CREATOR
-            = new Parcelable.Creator<KeyAttestationApplicationId>() {
-        @Override
-        public KeyAttestationApplicationId createFromParcel(Parcel source) {
-            return new KeyAttestationApplicationId(source);
-        }
-
-        @Override
-        public KeyAttestationApplicationId[] newArray(int size) {
-            return new KeyAttestationApplicationId[size];
-        }
-    };
-
-    KeyAttestationApplicationId(Parcel source) {
-        mAttestationPackageInfos = source.createTypedArray(KeyAttestationPackageInfo.CREATOR);
-    }
-}
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
deleted file mode 100644
index c0b8d8d..0000000
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
+++ /dev/null
@@ -1,95 +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.security.keymaster;
-
-import android.content.pm.Signature;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * @hide
- * This class constitutes and excerpt from the PackageManager's PackageInfo for the purpose of
- * key attestation. It is part of the KeyAttestationApplicationId, which is used by
- * keystore to identify the caller of the keystore API towards a remote party.
- */
-public class KeyAttestationPackageInfo implements Parcelable {
-    private final String mPackageName;
-    private final long mPackageVersionCode;
-    private final Signature[] mPackageSignatures;
-
-    /**
-     * @param mPackageName
-     * @param mPackageVersionCode
-     * @param mPackageSignatures
-     */
-    public KeyAttestationPackageInfo(
-            String mPackageName, long mPackageVersionCode, Signature[] mPackageSignatures) {
-        super();
-        this.mPackageName = mPackageName;
-        this.mPackageVersionCode = mPackageVersionCode;
-        this.mPackageSignatures = mPackageSignatures;
-    }
-    /**
-     * @return the mPackageName
-     */
-    public String getPackageName() {
-        return mPackageName;
-    }
-    /**
-     * @return the mPackageVersionCode
-     */
-    public long getPackageVersionCode() {
-        return mPackageVersionCode;
-    }
-    /**
-     * @return the mPackageSignatures
-     */
-    public Signature[] getPackageSignatures() {
-        return mPackageSignatures;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mPackageName);
-        dest.writeLong(mPackageVersionCode);
-        dest.writeTypedArray(mPackageSignatures, flags);
-    }
-
-    public static final @android.annotation.NonNull Parcelable.Creator<KeyAttestationPackageInfo> CREATOR
-            = new Parcelable.Creator<KeyAttestationPackageInfo>() {
-        @Override
-        public KeyAttestationPackageInfo createFromParcel(Parcel source) {
-            return new KeyAttestationPackageInfo(source);
-        }
-
-        @Override
-        public KeyAttestationPackageInfo[] newArray(int size) {
-            return new KeyAttestationPackageInfo[size];
-        }
-    };
-
-    private KeyAttestationPackageInfo(Parcel source) {
-        mPackageName = source.readString();
-        mPackageVersionCode = source.readLong();
-        mPackageSignatures = source.createTypedArray(Signature.CREATOR);
-    }
-}
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 115894f..a29bf7a 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -18,6 +18,7 @@
 
 import static android.view.autofill.Helper.sDebug;
 
+import android.annotation.Hide;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -26,6 +27,7 @@
 import android.annotation.TestApi;
 import android.content.ClipData;
 import android.content.IntentSender;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArrayMap;
@@ -187,6 +189,9 @@
     @Nullable private final InlinePresentation mInlinePresentation;
     @Nullable private final InlinePresentation mInlineTooltipPresentation;
     private final IntentSender mAuthentication;
+
+    @Nullable private final Bundle mAuthenticationExtras;
+
     @Nullable String mId;
 
     /**
@@ -224,6 +229,7 @@
         mInlinePresentation = inlinePresentation;
         mInlineTooltipPresentation = inlineTooltipPresentation;
         mAuthentication = authentication;
+        mAuthenticationExtras = null;
         mId = id;
     }
 
@@ -246,6 +252,7 @@
         mInlinePresentation = dataset.mInlinePresentation;
         mInlineTooltipPresentation = dataset.mInlineTooltipPresentation;
         mAuthentication = dataset.mAuthentication;
+        mAuthenticationExtras = dataset.mAuthenticationExtras;
         mId = dataset.mId;
         mAutofillDatatypes = dataset.mAutofillDatatypes;
     }
@@ -264,6 +271,7 @@
         mInlinePresentation = builder.mInlinePresentation;
         mInlineTooltipPresentation = builder.mInlineTooltipPresentation;
         mAuthentication = builder.mAuthentication;
+        mAuthenticationExtras = builder.mAuthenticationExtras;
         mId = builder.mId;
         mAutofillDatatypes = builder.mAutofillDatatypes;
     }
@@ -345,6 +353,12 @@
     }
 
     /** @hide */
+    @Hide
+    public @Nullable Bundle getAuthenticationExtras() {
+        return mAuthenticationExtras;
+    }
+
+    /** @hide */
     @TestApi
     public boolean isEmpty() {
         return mFieldIds == null || mFieldIds.isEmpty();
@@ -401,6 +415,9 @@
         if (mAuthentication != null) {
             builder.append(", hasAuthentication");
         }
+        if (mAuthenticationExtras != null) {
+            builder.append(", hasAuthenticationExtras");
+        }
         if (mAutofillDatatypes != null) {
             builder.append(", autofillDatatypes=").append(mAutofillDatatypes);
         }
@@ -454,6 +471,8 @@
         @Nullable private InlinePresentation mInlinePresentation;
         @Nullable private InlinePresentation mInlineTooltipPresentation;
         private IntentSender mAuthentication;
+
+        private Bundle mAuthenticationExtras;
         private boolean mDestroyed;
         @Nullable private String mId;
 
@@ -624,6 +643,25 @@
         }
 
         /**
+         * Sets extras to be associated with the {@code authentication} intent sender, to be
+         * set on the intent that is fired through the intent sender.
+         *
+         * Autofill providers can set any extras they wish to receive directly on the intent
+         * that is used to create the {@code authentication}. This is an internal API, to be
+         * used by the platform to associate data with a given dataset. These extras will be
+         * merged with the {@code clientState} and sent as part of the fill in intent when
+         * the {@code authentication} intentSender is invoked.
+         *
+         * @hide
+         */
+        @Hide
+        public @NonNull Builder setAuthenticationExtras(@Nullable Bundle authenticationExtra) {
+            throwIfDestroyed();
+            mAuthenticationExtras = authenticationExtra;
+            return this;
+        }
+
+        /**
          * Sets the id for the dataset so its usage can be tracked.
          *
          * <p>Dataset usage can be tracked for 2 purposes:
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 8cf2ce4..7ec1483 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -97,8 +97,6 @@
      */
     public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10;
 
-    // The flag value 0x20 has been defined in AutofillManager.
-
     /**
      * Indicates the request supports fill dialog presentation for the fields, the
      * system will send the request when the activity just started.
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
index 3b757d6..33978be 100644
--- a/core/java/android/service/controls/Control.java
+++ b/core/java/android/service/controls/Control.java
@@ -50,7 +50,7 @@
  * and zone. Some of these values are defined by the user and/or the {@link ControlsProviderService}
  * and will be used to display the control as well as group them for management.
  * <p>
- * Each object will have an associated {@link DeviceTypes.DeviceType}. This will determine the icons and colors
+ * Each object will have an associated {@link DeviceTypes}. This will determine the icons and colors
  * used to display it.
  * <p>
  * An {@link Intent} linking to the provider Activity that expands on this {@link Control} and
@@ -420,7 +420,7 @@
      * This fixes the values relating to state of the {@link Control} as required by
      * {@link ControlsProviderService#createPublisherForAllAvailable}:
      * <ul>
-     *     <li> Status: {@link Status#STATUS_UNKNOWN}
+     *     <li> Status: {@link #STATUS_UNKNOWN}
      *     <li> Control template: {@link ControlTemplate#getNoTemplateObject}
      *     <li> Status text: {@code ""}
      *     <li> Auth Required: {@code true}
@@ -620,7 +620,7 @@
      *     <li> Device type: {@link DeviceTypes#TYPE_UNKNOWN}
      *     <li> Title: {@code ""}
      *     <li> Subtitle: {@code ""}
-     *     <li> Status: {@link Status#STATUS_UNKNOWN}
+     *     <li> Status: {@link #STATUS_UNKNOWN}
      *     <li> Control template: {@link ControlTemplate#getNoTemplateObject}
      *     <li> Status text: {@code ""}
      *     <li> Auth Required: {@code true}
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index fce87db..0272bb9 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -155,7 +155,7 @@
      * The user has interacted with a Control. The action is dictated by the type of
      * {@link ControlAction} that was sent. A response can be sent via
      * {@link Consumer#accept}, with the Integer argument being one of the provided
-     * {@link ControlAction.ResponseResult}. The Integer should indicate whether the action
+     * {@link ControlAction} response results. The Integer should indicate whether the action
      * was received successfully, or if additional prompts should be presented to
      * the user. Any visual control updates should be sent via the Publisher.
 
diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java
index 10f526d..4e38222 100644
--- a/core/java/android/service/controls/actions/ControlAction.java
+++ b/core/java/android/service/controls/actions/ControlAction.java
@@ -154,7 +154,7 @@
     public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 5;
 
     /**
-     * The {@link ActionType} associated with this class.
+     * The action type associated with this class.
      */
     public abstract @ActionType int getActionType();
 
diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java
index 3902d6a..0dd950d 100644
--- a/core/java/android/service/controls/templates/ControlTemplate.java
+++ b/core/java/android/service/controls/templates/ControlTemplate.java
@@ -137,7 +137,7 @@
     }
 
     /**
-     * The {@link TemplateType} associated with this class.
+     * The template type associated with this class.
      */
     public abstract @TemplateType int getTemplateType();
 
diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java
index be7b722..a2b0a66 100644
--- a/core/java/android/service/credentials/CredentialProviderService.java
+++ b/core/java/android/service/credentials/CredentialProviderService.java
@@ -153,6 +153,18 @@
     public static final String EXTRA_BEGIN_GET_CREDENTIAL_REQUEST =
             "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST";
 
+    /**
+     * The key to autofillId associated with the requested credential option and the corresponding
+     * credential entry. The associated autofillId will be contained inside the candidate query
+     * bundle of {@link android.credentials.CredentialOption} if requested through the
+     * {@link com.android.credentialmanager.autofill.CredentialAutofillService}. The resulting
+     * credential entry will  contain the autofillId inside its framework extras intent.
+     *
+     * @hide
+     */
+    public static final String EXTRA_AUTOFILL_ID =
+            "android.service.credentials.extra.AUTOFILL_ID";
+
     private static final String TAG = "CredProviderService";
 
      /**
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 07f8aac..1cfff14 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -2007,6 +2007,20 @@
             return mSmartActions == null ? Collections.emptyList() : mSmartActions;
         }
 
+
+        /**
+         * Sets the smart {@link Notification.Action} objects.
+         *
+         * Should ONLY be used in cases where smartActions need to be removed from, then restored
+         * on, Ranking objects during Parceling, when they are transmitted between processes via
+         * Shared Memory.
+         *
+         * @hide
+         */
+        public void setSmartActions(@Nullable ArrayList<Notification.Action> smartActions) {
+            mSmartActions = smartActions;
+        }
+
         /**
          * Returns a list of smart replies that can be added by the
          * {@link NotificationAssistantService}
@@ -2353,11 +2367,9 @@
 
         /**
          * Get a reference to the actual Ranking object corresponding to the key.
-         * Used only by unit tests.
          *
          * @hide
          */
-        @VisibleForTesting
         public Ranking getRawRankingObject(String key) {
             return mRankings.get(key);
         }
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index f3b4c6d..79c8fb4 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -17,7 +17,8 @@
 
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
-import android.annotation.TestApi;
+import android.app.Notification;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SharedMemory;
@@ -29,13 +30,15 @@
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Represents an update to notification rankings.
+ *
  * @hide
  */
 @SuppressLint({"ParcelNotFinal", "ParcelCreator"})
-@TestApi
 public class NotificationRankingUpdate implements Parcelable {
     private final NotificationListenerService.RankingMap mRankingMap;
 
@@ -64,6 +67,7 @@
                 // The ranking map should be stored in shared memory when it is parceled, so we
                 // unwrap the SharedMemory object.
                 mRankingMapFd = in.readParcelable(getClass().getClassLoader(), SharedMemory.class);
+                Bundle smartActionsBundle = in.readBundle(getClass().getClassLoader());
 
                 // In the case that the ranking map can't be read, readParcelable may return null.
                 // In this case, we set mRankingMap to null;
@@ -82,15 +86,20 @@
                 mapParcel.unmarshall(payload, 0, payload.length);
                 mapParcel.setDataPosition(0);
 
-                mRankingMap = mapParcel.readParcelable(getClass().getClassLoader(),
-                        android.service.notification.NotificationListenerService.RankingMap.class);
+                mRankingMap =
+                        mapParcel.readParcelable(
+                                getClass().getClassLoader(),
+                                NotificationListenerService.RankingMap.class);
+
+                addSmartActionsFromBundleToRankingMap(smartActionsBundle);
+
             } catch (ErrnoException e) {
                 // TODO(b/284297289): remove throw when associated flag is moved to droidfood, to
                 // avoid crashes; change to Log.wtf.
                 throw new RuntimeException(e);
             } finally {
                 mapParcel.recycle();
-                if (buffer != null) {
+                if (buffer != null && mRankingMapFd != null) {
                     mRankingMapFd.unmap(buffer);
                     mRankingMapFd.close();
                 }
@@ -102,10 +111,33 @@
     }
 
     /**
-     * Confirms that the SharedMemory file descriptor is closed. Should only be used for testing.
+     * For each key in the rankingMap, extracts lists of smart actions stored in the provided
+     * bundle and adds them to the corresponding Ranking object in the provided ranking
+     * map, then returns the rankingMap.
+     *
      * @hide
      */
-    @TestApi
+    private void addSmartActionsFromBundleToRankingMap(Bundle smartActionsBundle) {
+        if (smartActionsBundle == null) {
+            return;
+        }
+
+        String[] rankingMapKeys = mRankingMap.getOrderedKeys();
+        for (int i = 0; i < rankingMapKeys.length; i++) {
+            String key = rankingMapKeys[i];
+            ArrayList<Notification.Action> smartActions =
+                    smartActionsBundle.getParcelableArrayList(key, Notification.Action.class);
+            // Get the ranking object from the ranking map.
+            NotificationListenerService.Ranking ranking = mRankingMap.getRawRankingObject(key);
+            ranking.setSmartActions(smartActions);
+        }
+    }
+
+    /**
+     * Confirms that the SharedMemory file descriptor is closed. Should only be used for testing.
+     *
+     * @hide
+     */
     public final boolean isFdNotNullAndClosed() {
         return mRankingMapFd != null && mRankingMapFd.getFd() == -1;
     }
@@ -145,9 +177,45 @@
         if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(
                 SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) {
             final Parcel mapParcel = Parcel.obtain();
+            ArrayList<NotificationListenerService.Ranking> marshalableRankings = new ArrayList<>();
+            Bundle smartActionsBundle = new Bundle();
+
+            // We need to separate the SmartActions from the RankingUpdate objects.
+            // SmartActions can contain PendingIntents, which cannot be marshalled,
+            // so we extract them to send separately.
+            String[] rankingMapKeys = mRankingMap.getOrderedKeys();
+            for (int i = 0; i < rankingMapKeys.length; i++) {
+                String key = rankingMapKeys[i];
+                NotificationListenerService.Ranking ranking = mRankingMap.getRawRankingObject(key);
+
+                // Removes the SmartActions and stores them in a separate map.
+                // Note that getSmartActions returns a Collections.emptyList() if there are no
+                // smart actions, and we don't want to needlessly store an empty list object, so we
+                // check for null before storing.
+                List<Notification.Action> smartActions = ranking.getSmartActions();
+                if (!smartActions.isEmpty()) {
+                    smartActionsBundle.putParcelableList(key, smartActions);
+                }
+
+                // Create a copy of the ranking object that doesn't have the smart actions.
+                NotificationListenerService.Ranking rankingCopy =
+                        new NotificationListenerService.Ranking();
+                rankingCopy.populate(ranking);
+                rankingCopy.setSmartActions(null);
+                marshalableRankings.add(rankingCopy);
+            }
+
+            // Create a new marshalable RankingMap.
+            NotificationListenerService.RankingMap marshalableRankingMap =
+                    new NotificationListenerService.RankingMap(
+                            marshalableRankings.toArray(
+                                    new NotificationListenerService.Ranking[0]
+                            )
+                    );
+
             try {
                 // Parcels the ranking map and measures its size.
-                mapParcel.writeParcelable(mRankingMap, flags);
+                mapParcel.writeParcelable(marshalableRankingMap, flags);
                 int mapSize = mapParcel.dataSize();
 
                 // Creates a new SharedMemory object with enough space to hold the ranking map.
@@ -158,15 +226,14 @@
 
                 // Gets a read/write buffer mapping the entire shared memory region.
                 final ByteBuffer buffer = mRankingMapFd.mapReadWrite();
-
                 // Puts the ranking map into the shared memory region buffer.
                 buffer.put(mapParcel.marshall(), 0, mapSize);
-
                 // Protects the region from being written to, by setting it to be read-only.
                 mRankingMapFd.setProtect(OsConstants.PROT_READ);
-
                 // Puts the SharedMemory object in the parcel.
                 out.writeParcelable(mRankingMapFd, flags);
+                // Writes the Parceled smartActions separately.
+                out.writeBundle(smartActionsBundle);
             } catch (ErrnoException e) {
                 // TODO(b/284297289): remove throw when associated flag is moved to droidfood, to
                 // avoid crashes; change to Log.wtf.
@@ -180,8 +247,8 @@
     }
 
     /**
-    * @hide
-    */
+     * @hide
+     */
     public static final @android.annotation.NonNull Parcelable.Creator<NotificationRankingUpdate> CREATOR
             = new Parcelable.Creator<NotificationRankingUpdate>() {
         public NotificationRankingUpdate createFromParcel(Parcel parcel) {
diff --git a/core/java/android/service/voice/flags/flags.aconfig b/core/java/android/service/voice/flags/flags.aconfig
new file mode 100644
index 0000000..c414ef8
--- /dev/null
+++ b/core/java/android/service/voice/flags/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.service.voice.flags"
+
+flag {
+    name: "allow_training_data_egress_from_hds"
+    namespace: "machine_learning"
+    description: "This flag allows the hotword detection service to egress training data to the default assistant."
+    bug: "296074924"
+}
diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
index 49e00d6..7befbfb 100644
--- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java
+++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
@@ -151,7 +151,7 @@
      */
     @NonNull public abstract List<String> onGetRequestedPackages();
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true);
+    private final Handler mHandler = Handler.createAsync(Looper.getMainLooper());
     @Nullable private RemoteCallback mCallback;
 
     @Override
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index f6309f2..cf1156d 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -401,7 +401,7 @@
 
     /**
      * Listen for call disconnect causes which contains {@link DisconnectCause} and
-     * {@link PreciseDisconnectCause}.
+     * the precise disconnect cause.
      *
      * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
      * or the calling app has carrier privileges
@@ -851,8 +851,8 @@
      * subId. Otherwise, this callback applies to
      * {@link SubscriptionManager#getDefaultSubscriptionId()}.
      *
-     * @param disconnectCause {@link DisconnectCause}.
-     * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
+     * @param disconnectCause the disconnect cause
+     * @param preciseDisconnectCause the precise disconnect cause
      * @deprecated Use {@link TelephonyCallback.CallDisconnectCauseListener} instead.
      */
     @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java
index fb2d771..7b48a16 100644
--- a/core/java/android/telephony/SubscriptionPlan.java
+++ b/core/java/android/telephony/SubscriptionPlan.java
@@ -221,7 +221,7 @@
     }
 
     /**
-     * Return an array containing all {@link NetworkType}s this SubscriptionPlan applies to.
+     * Return an array containing all network types this SubscriptionPlan applies to.
      * @see TelephonyManager for network types values
      */
     public @NonNull @NetworkType int[] getNetworkTypes() {
@@ -365,7 +365,7 @@
          * Set the network types this SubscriptionPlan applies to. By default the plan will apply
          * to all network types. An empty array means this plan applies to no network types.
          *
-         * @param networkTypes an array of all {@link NetworkType}s that apply to this plan.
+         * @param networkTypes an array of all network types that apply to this plan.
          * @see TelephonyManager for network type values
          */
         public @NonNull Builder setNetworkTypes(@NonNull @NetworkType int[] networkTypes) {
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index 7ada058..19bcf28 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -948,8 +948,8 @@
          * subscription ID. Otherwise, this callback applies to
          * {@link SubscriptionManager#getDefaultSubscriptionId()}.
          *
-         * @param disconnectCause        {@link DisconnectCause}.
-         * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
+         * @param disconnectCause        the disconnect cause
+         * @param preciseDisconnectCause the precise disconnect cause
          */
         @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
         void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause,
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index e2c5539..0063d13 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -238,7 +238,7 @@
     }
 
     /**
-     * To check the SDK version for {@link #listenFromListener}.
+     * To check the SDK version for {@code #listenFromListener}.
      */
     @ChangeId
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 2b3a081..8862f1d 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -16,6 +16,10 @@
 
 package android.text;
 
+import static com.android.text.flags.Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN;
+import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
+
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -280,6 +284,7 @@
          * @see android.widget.TextView#setLineBreakWordStyle
          */
         @NonNull
+        @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
         public Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
             mLineBreakConfig = lineBreakConfig;
             return this;
@@ -303,6 +308,7 @@
          * @see Layout.Builder#setUseBoundsForWidth(boolean)
          */
         @NonNull
+        @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
         public Builder setUseBoundsForWidth(boolean useBoundsForWidth) {
             mUseBoundsForWidth = useBoundsForWidth;
             return this;
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index c585734..94c8eaf 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -29,6 +29,7 @@
 import android.graphics.fonts.FontFamily.Builder.VariableFontFamilyType;
 import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
+import android.icu.util.ULocale;
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.Parcel;
@@ -39,6 +40,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.Objects;
 
 
@@ -58,6 +60,7 @@
     private final @NonNull List<FontFamily> mFamilies;
     private final @NonNull List<Alias> mAliases;
     private final @NonNull List<NamedFamilyList> mNamedFamilyLists;
+    private final @NonNull List<Customization.LocaleFallback> mLocaleFallbackCustomizations;
     private final long mLastModifiedTimeMillis;
     private final int mConfigVersion;
 
@@ -71,10 +74,12 @@
      */
     public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> aliases,
             @NonNull List<NamedFamilyList> namedFamilyLists,
+            @NonNull List<Customization.LocaleFallback> localeFallbackCustomizations,
             long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion) {
         mFamilies = families;
         mAliases = aliases;
         mNamedFamilyLists = namedFamilyLists;
+        mLocaleFallbackCustomizations = localeFallbackCustomizations;
         mLastModifiedTimeMillis = lastModifiedTimeMillis;
         mConfigVersion = configVersion;
     }
@@ -84,7 +89,8 @@
      */
     public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> aliases,
             long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion) {
-        this(families, aliases, Collections.emptyList(), lastModifiedTimeMillis, configVersion);
+        this(families, aliases, Collections.emptyList(), Collections.emptyList(),
+                lastModifiedTimeMillis, configVersion);
     }
 
 
@@ -113,6 +119,18 @@
     }
 
     /**
+     * Returns a locale fallback customizations.
+     *
+     * This field is used for creating the system fallback in the system server. This field is
+     * always empty in the application process.
+     *
+     * @hide
+     */
+    public @NonNull List<Customization.LocaleFallback> getLocaleFallbackCustomizations() {
+        return mLocaleFallbackCustomizations;
+    }
+
+    /**
      * Returns the last modified time in milliseconds.
      *
      * This is a value of {@link System#currentTimeMillis()} when the system font configuration was
@@ -169,7 +187,9 @@
             source.readTypedList(familyLists, NamedFamilyList.CREATOR);
             long lastModifiedDate = source.readLong();
             int configVersion = source.readInt();
-            return new FontConfig(families, aliases, familyLists, lastModifiedDate, configVersion);
+            return new FontConfig(families, aliases, familyLists,
+                    Collections.emptyList(),  // Don't need to pass customization to API caller.
+                    lastModifiedDate, configVersion);
         }
 
         @Override
@@ -813,4 +833,129 @@
                     + '}';
         }
     }
+
+    /** @hide */
+    public static class Customization {
+        private Customization() {}  // Singleton
+
+        /**
+         * A class that represents customization of locale fallback
+         *
+         * This class represents a vendor customization of new-locale-family.
+         *
+         * <pre>
+         * <family customizationType="new-locale-family" operation="prepend" lang="ja-JP">
+         *     <font weight="400" style="normal">MyAlternativeFont.ttf
+         *         <axis tag="wght" stylevalue="400"/>
+         *     </font>
+         * </family>
+         * </pre>
+         *
+         * The operation can be one of prepend, replace or append. The operation prepend means that
+         * the new font family is inserted just before the original font family. The original font
+         * family is still in the fallback. The operation replace means that the original font
+         * family is replaced with new font family. The original font family is removed from the
+         * fallback. The operation append means that the new font family is inserted just after the
+         * original font family. The original font family is still in the fallback.
+         *
+         * The lang attribute is a BCP47 compliant language tag. The font fallback mainly uses ISO
+         * 15924 script code for matching. If the script code is missing, most likely script code
+         * will be used.
+         */
+        public static class LocaleFallback {
+            private final Locale mLocale;
+            private final int mOperation;
+            private final FontFamily mFamily;
+            private final String mScript;
+
+            public static final int OPERATION_PREPEND = 0;
+            public static final int OPERATION_APPEND = 1;
+            public static final int OPERATION_REPLACE = 2;
+
+            /** @hide */
+            @Retention(SOURCE)
+            @IntDef(prefix = { "OPERATION_" }, value = {
+                    OPERATION_PREPEND,
+                    OPERATION_APPEND,
+                    OPERATION_REPLACE
+            })
+            public @interface Operation {}
+
+
+            public LocaleFallback(@NonNull Locale locale, @Operation int operation,
+                    @NonNull FontFamily family) {
+                mLocale = locale;
+                mOperation = operation;
+                mFamily = family;
+                mScript = resolveScript(locale);
+            }
+
+            /**
+             * A customization target locale.
+             * @return a locale
+             */
+            public @NonNull Locale getLocale() {
+                return mLocale;
+            }
+
+            /**
+             * An operation to be applied to the original font family.
+             *
+             * The operation can be one of {@link #OPERATION_PREPEND}, {@link #OPERATION_REPLACE} or
+             * {@link #OPERATION_APPEND}.
+             *
+             * The operation prepend ({@link #OPERATION_PREPEND}) means that the new font family is
+             * inserted just before the original font family. The original font family is still in
+             * the fallback.
+             *
+             * The operation replace ({@link #OPERATION_REPLACE}) means that the original font
+             * family is replaced with new font family. The original font family is removed from the
+             * fallback.
+             *
+             * The operation append ({@link #OPERATION_APPEND}) means that the new font family is
+             * inserted just after the original font family. The original font family is still in
+             * the fallback.
+             *
+             * @return an operation.
+             */
+            public @Operation int getOperation() {
+                return mOperation;
+            }
+
+            /**
+             * Returns a family to be inserted or replaced to the fallback.
+             *
+             * @return a family
+             */
+            public @NonNull FontFamily getFamily() {
+                return mFamily;
+            }
+
+            /**
+             * Returns a script of the locale. If the script is missing in the given locale, the
+             * most likely locale is returned.
+             */
+            public @NonNull String getScript() {
+                return mScript;
+            }
+
+            @Override
+            public String toString() {
+                return "LocaleFallback{"
+                        + "mLocale=" + mLocale
+                        + ", mOperation=" + mOperation
+                        + ", mFamily=" + mFamily
+                        + '}';
+            }
+        }
+    }
+
+    /** @hide */
+    public static String resolveScript(Locale locale) {
+        String script = locale.getScript();
+        if (script != null && !script.isEmpty()) {
+            return script;
+        }
+        return ULocale.addLikelySubtags(ULocale.forLocale(locale)).getScript();
+    }
 }
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
index c1d0e9b9..ac5eb3c 100644
--- a/core/java/android/text/MeasuredParagraph.java
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -16,6 +16,9 @@
 
 package android.text;
 
+import static com.android.text.flags.Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN;
+
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -416,10 +419,12 @@
      * @hide
      */
     @TestApi
+    @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
     public interface StyleRunCallback {
         /**
          * Called when a single style run is identified.
          */
+        @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
         void onAppendStyleRun(@NonNull Paint paint,
                 @Nullable LineBreakConfig lineBreakConfig, @IntRange(from = 0) int length,
                 boolean isRtl);
@@ -427,6 +432,7 @@
         /**
          * Called when a single replacement run is identified.
          */
+        @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
         void onAppendReplacementRun(@NonNull Paint paint,
                 @IntRange(from = 0) int length, @Px @FloatRange(from = 0) float width);
     }
@@ -488,6 +494,7 @@
     @SuppressLint("ExecutorRegistration")
     @TestApi
     @NonNull
+    @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
     public static MeasuredParagraph buildForStaticLayoutTest(
             @NonNull TextPaint paint,
             @Nullable LineBreakConfig lineBreakConfig,
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e3c72c9..01279ce 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,6 +16,9 @@
 
 package android.text;
 
+import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
+
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -439,6 +442,7 @@
          * @see Layout.Builder#setUseBoundsForWidth(boolean)
          */
         @NonNull
+        @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
         public Builder setUseBoundsForWidth(boolean useBoundsForWidth) {
             mUseBoundsForWidth = useBoundsForWidth;
             return this;
diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java
index 536e3cc..9edf298 100644
--- a/core/java/android/text/TextFlags.java
+++ b/core/java/android/text/TextFlags.java
@@ -62,6 +62,18 @@
     };
 
     /**
+     * List of the default values of the text flags.
+     *
+     * The order must be the same to the TEXT_ACONFIG_FLAGS.
+     */
+    public static final boolean[] TEXT_ACONFIG_DEFAULT_VALUE = {
+            Flags.deprecateFontsXml(),
+            Flags.noBreakNoHyphenationSpan(),
+            Flags.phraseStrictFallback(),
+            Flags.useBoundsForWidth(),
+    };
+
+    /**
      * Get a key for the feature flag.
      */
     public static String getKeyForFlag(@NonNull String flag) {
diff --git a/core/java/android/text/flags/custom_locale_fallback.aconfig b/core/java/android/text/flags/custom_locale_fallback.aconfig
new file mode 100644
index 0000000..52fe883
--- /dev/null
+++ b/core/java/android/text/flags/custom_locale_fallback.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.text.flags"
+
+flag {
+  name: "custom_locale_fallback"
+  namespace: "text"
+  description: "A feature flag that adds custom locale fallback to the vendor customization XML. This enables vendors to add their locale specific fonts, e.g. Japanese font."
+  is_fixed_read_only: true
+  bug: "278768958"
+}
diff --git a/core/java/android/text/flags/deprecate_fonts_xml.aconfig b/core/java/android/text/flags/deprecate_fonts_xml.aconfig
index 58dc210..5362138 100644
--- a/core/java/android/text/flags/deprecate_fonts_xml.aconfig
+++ b/core/java/android/text/flags/deprecate_fonts_xml.aconfig
@@ -4,5 +4,7 @@
   name: "deprecate_fonts_xml"
   namespace: "text"
   description: "Feature flag for deprecating fonts.xml. By setting true for this feature flag, the new font configuration XML, /system/etc/font_fallback.xml is used. The new XML has a new syntax and flexibility of variable font declarations, but it is not compatible with the apps that reads fonts.xml. So, fonts.xml is maintained as a subset of the font_fallback.xml"
+  # Make read only, as it could be used before the Settings provider is initialized.
+  is_fixed_read_only: true
   bug: "281769620"
 }
diff --git a/core/java/android/text/flags/fix_line_height_for_locale.aconfig b/core/java/android/text/flags/fix_line_height_for_locale.aconfig
new file mode 100644
index 0000000..8696bfa
--- /dev/null
+++ b/core/java/android/text/flags/fix_line_height_for_locale.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.text.flags"
+
+flag {
+  name: "fix_line_height_for_locale"
+  namespace: "text"
+  description: "Feature flag that preserve the line height of the TextView and EditText even if the the locale is different from Latin"
+  bug: "303326708"
+}
diff --git a/core/java/android/text/flags/optimized_font_loading.aconfig b/core/java/android/text/flags/optimized_font_loading.aconfig
new file mode 100644
index 0000000..0e4a69f
--- /dev/null
+++ b/core/java/android/text/flags/optimized_font_loading.aconfig
@@ -0,0 +1,11 @@
+package: "com.android.text.flags"
+
+flag {
+  name: "use_optimized_boottime_font_loading"
+  namespace: "text"
+  description: "Feature flag ensuring that font is loaded once and asynchronously."
+  # Make read only, as font loading is in the critical boot path which happens before the read-write
+  # flags propagate to the device.
+  is_fixed_read_only: true
+  bug: "304406888"
+}
diff --git a/core/java/android/text/style/LineBreakConfigSpan.java b/core/java/android/text/style/LineBreakConfigSpan.java
index 25c1db4d..682ffa1 100644
--- a/core/java/android/text/style/LineBreakConfigSpan.java
+++ b/core/java/android/text/style/LineBreakConfigSpan.java
@@ -71,6 +71,10 @@
             .setHyphenation(LineBreakConfig.HYPHENATION_DISABLED)
             .build();
 
+    private static final LineBreakConfig sNoBreakConfig = new LineBreakConfig.Builder()
+            .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NO_BREAK)
+            .build();
+
     /**
      * A specialized {@link LineBreakConfigSpan} that used for preventing hyphenation.
      */
@@ -84,4 +88,24 @@
             super(sNoHyphenationConfig);
         }
     }
+
+    /**
+     * A specialized {@link LineBreakConfigSpan} that used for preventing line break.
+     *
+     * This is useful when you want to preserve some words in the same line.
+     * Note that even if this style is specified, the grapheme based line break is still performed
+     * for preventing clipping text.
+     *
+     * @see LineBreakConfigSpan
+     */
+    @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
+    public static final class NoBreakSpan extends LineBreakConfigSpan {
+        /**
+         * Construct a new {@link NoBreakSpan}.
+         */
+        @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
+        public NoBreakSpan() {
+            super(sNoBreakConfig);
+        }
+    }
 }
diff --git a/core/java/android/util/Base64.java b/core/java/android/util/Base64.java
index 92abd7c..33cc5e3 100644
--- a/core/java/android/util/Base64.java
+++ b/core/java/android/util/Base64.java
@@ -26,6 +26,7 @@
  * href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
  * href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
  */
+@android.ravenwood.annotations.RavenwoodWholeClassKeep
 public class Base64 {
     /**
      * Default values for encoder/decoder flags.
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 1ab055a..a74cbe4 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -16,9 +16,11 @@
 
 package android.view;
 
+import static android.view.flags.Flags.FLAG_EXPECTED_PRESENTATION_TIME_API;
 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -695,6 +697,7 @@
      */
     @TestApi
     @UnsupportedAppUsage
+    @FlaggedApi(FLAG_EXPECTED_PRESENTATION_TIME_API)
     public long getFrameTimeNanos() {
         synchronized (mLock) {
             if (!mCallbacksRunning) {
diff --git a/core/java/android/view/IDecorViewGestureListener.aidl b/core/java/android/view/IDecorViewGestureListener.aidl
new file mode 100644
index 0000000..1022dbf
--- /dev/null
+++ b/core/java/android/view/IDecorViewGestureListener.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Listener for changes to gesture interception detector running at DecorView.
+ *
+ * {@hide}
+ */
+oneway interface IDecorViewGestureListener {
+    /**
+     * Called when a DecorView has started intercepting gesture.
+     *
+     * @param windowToken Where did this gesture interception result comes from.
+     * @param intercepted Whether the gesture interception detector has started interception.
+     */
+    void onInterceptionChanged(in IBinder windowToken, in boolean intercepted);
+}
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index c4d3070..a150187 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -23,6 +23,8 @@
 import android.window.PictureInPictureSurfaceTransaction;
 import android.window.TaskSnapshot;
 
+import com.android.internal.os.IResultReceiver;
+
 /**
  * Passed to the {@link IRecentsAnimationRunner} in order for the runner to control to let the
  * runner control certain aspects of the recents animation, and to notify window manager when the
@@ -58,7 +60,7 @@
      *                          top resumed app, false otherwise.
      */
     @UnsupportedAppUsage
-    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint);
+    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint, in IResultReceiver finishCb);
 
     /**
      * Called by the handler to indicate that the recents animation input consumer should be
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index cccac95..c10fc9f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -48,6 +48,7 @@
 import android.view.RemoteAnimationAdapter;
 import android.view.IRotationWatcher;
 import android.view.ISystemGestureExclusionListener;
+import android.view.IDecorViewGestureListener;
 import android.view.IWallpaperVisibilityListener;
 import android.view.IWindow;
 import android.view.IWindowSession;
@@ -1062,4 +1063,18 @@
      @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
              + ".permission.ACCESS_SURFACE_FLINGER)")
     boolean replaceContentOnDisplay(int displayId, in SurfaceControl sc);
+
+    /**
+     * Registers a DecorView gesture listener for a given display.
+     */
+    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+            + ".permission.MONITOR_INPUT)")
+    void registerDecorViewGestureListener(IDecorViewGestureListener listener, int displayId);
+
+    /**
+     * Unregisters a DecorView gesture listener for a given display.
+     */
+    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+            + ".permission.MONITOR_INPUT)")
+    void unregisterDecorViewGestureListener(IDecorViewGestureListener listener, int displayId);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 83de2a0..7acf2f8 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -284,6 +284,11 @@
     oneway void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
 
     /**
+     * Called when the DecorView gesture interception state has changed.
+     */
+    oneway void reportDecorViewGestureInterceptionChanged(IWindow window, in boolean intercepted);
+
+    /**
      * Called when the keep-clear areas for this window have changed.
      */
     oneway void reportKeepClearAreasChanged(IWindow window, in List<Rect> restricted,
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 2761aae..45b3fdd 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static com.android.window.flags.Flags.surfaceTrustedOverlay;
+
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.graphics.Matrix;
@@ -35,7 +37,6 @@
  * @hide
  */
 public final class InputWindowHandle {
-
     /**
      * An internal annotation for all the {@link android.os.InputConfig} flags that can be
      * specified to {@link #inputConfig} to control the behavior of an input window. Only the
@@ -59,7 +60,6 @@
             InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER,
             InputConfig.IS_WALLPAPER,
             InputConfig.PAUSE_DISPATCHING,
-            InputConfig.TRUSTED_OVERLAY,
             InputConfig.WATCH_OUTSIDE_TOUCH,
             InputConfig.SLIPPERY,
             InputConfig.DISABLE_USER_ACTIVITY,
@@ -272,4 +272,13 @@
         }
         this.inputConfig &= ~inputConfig;
     }
+
+    public void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc,
+            boolean isTrusted) {
+        if (surfaceTrustedOverlay()) {
+            t.setTrustedOverlay(sc, isTrusted);
+        } else if (isTrusted) {
+            inputConfig |= InputConfig.TRUSTED_OVERLAY;
+        }
+    }
 }
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index cdf5eec3..70e1896 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -2197,6 +2197,9 @@
             float xOffset, float yOffset, float xPrecision, float yPrecision,
             long downTimeNanos, long eventTimeNanos,
             int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords) {
+        if (action == ACTION_CANCEL) {
+            flags |= FLAG_CANCELED;
+        }
         mNativePtr = nativeInitialize(mNativePtr, deviceId, source, displayId, action, flags,
                 edgeFlags, metaState, buttonState, classification, xOffset, yOffset,
                 xPrecision, yPrecision, downTimeNanos, eventTimeNanos, pointerCount, pointerIds,
@@ -2387,6 +2390,11 @@
         nativeSetFlags(mNativePtr, tainted ? flags | FLAG_TAINTED : flags & ~FLAG_TAINTED);
     }
 
+    private void setCanceled(boolean canceled) {
+        final int flags = getFlags();
+        nativeSetFlags(mNativePtr, canceled ? flags | FLAG_CANCELED : flags & ~FLAG_CANCELED);
+    }
+
     /** @hide */
     public  boolean isTargetAccessibilityFocus() {
         final int flags = getFlags();
@@ -3510,6 +3518,14 @@
      * Sets this event's action.
      */
     public final void setAction(int action) {
+        final int actionMasked = action & ACTION_MASK;
+        if (actionMasked == ACTION_CANCEL) {
+            setCanceled(true);
+        } else if (actionMasked == ACTION_POINTER_UP) {
+            // Do nothing - we don't know what the real intent here is
+        } else {
+            setCanceled(false);
+        }
         nativeSetAction(mNativePtr, action);
     }
 
@@ -4157,6 +4173,7 @@
     /** @hide */
     @Override
     public final void cancel() {
+        setCanceled(true);
         setAction(ACTION_CANCEL);
     }
 
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index a0a172d..5a28d5f 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -199,12 +199,33 @@
      * @throws NullPointerException if {@code listener} is null.
      */
     public ScaleGestureDetector(@NonNull Context context, @NonNull OnScaleGestureListener listener,
-                                @Nullable Handler handler) {
+            @Nullable Handler handler) {
+        this(context, ViewConfiguration.get(context).getScaledTouchSlop() * 2,
+                ViewConfiguration.get(context).getScaledMinimumScalingSpan(), handler, listener);
+    }
+
+    /**
+     * Creates a ScaleGestureDetector with span slop and min span.
+     *
+     * @param context the application's context.
+     * @param spanSlop the threshold for interpreting a touch movement as scaling.
+     * @param minSpan the minimum threshold of scaling span. The span could be
+     *                overridden by other usages to specify a different scaling span, for instance,
+     *                if you need pinch gestures to continue closer together than the default.
+     * @param listener the listener invoked for all the callbacks, this must not be null.
+     * @param handler the handler to use for running deferred listener events.
+     *
+     * @throws NullPointerException if {@code listener} is null.
+     *
+     * @hide
+     */
+    public ScaleGestureDetector(@NonNull Context context, @NonNull int spanSlop,
+            @NonNull int minSpan, @Nullable Handler handler,
+            @NonNull OnScaleGestureListener listener) {
         mContext = context;
         mListener = listener;
-        final ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
-        mSpanSlop = viewConfiguration.getScaledTouchSlop() * 2;
-        mMinSpan = viewConfiguration.getScaledMinimumScalingSpan();
+        mSpanSlop = spanSlop;
+        mMinSpan = minSpan;
         mHandler = handler;
         // Quick scale is enabled by default after JB_MR2
         final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index be6fb31..b080b71 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -123,7 +123,8 @@
     private static native long nativeMirrorSurface(long mirrorOfObject);
     private static native long nativeCreateTransaction();
     private static native long nativeGetNativeTransactionFinalizer();
-    private static native void nativeApplyTransaction(long transactionObj, boolean sync);
+    private static native void nativeApplyTransaction(long transactionObj, boolean sync,
+            boolean oneWay);
     private static native void nativeMergeTransaction(long transactionObj,
             long otherTransactionObj);
     private static native void nativeClearTransaction(long transactionObj);
@@ -1789,7 +1790,12 @@
         public float xDpi;
         public float yDpi;
 
+        // Some modes have peak refresh rate lower than the panel vsync rate.
         public float refreshRate;
+        // Fixed rate of vsync deadlines for the panel.
+        // This can be higher then the peak refresh rate for some panel technologies
+        // See: VrrConfig.aidl
+        public float vsyncRate;
         public long appVsyncOffsetNanos;
         public long presentationDeadlineNanos;
         public int[] supportedHdrTypes;
@@ -1810,6 +1816,7 @@
                     + ", xDpi=" + xDpi
                     + ", yDpi=" + yDpi
                     + ", refreshRate=" + refreshRate
+                    + ", vsyncRate=" + vsyncRate
                     + ", appVsyncOffsetNanos=" + appVsyncOffsetNanos
                     + ", presentationDeadlineNanos=" + presentationDeadlineNanos
                     + ", supportedHdrTypes=" + Arrays.toString(supportedHdrTypes)
@@ -1827,6 +1834,7 @@
                     && Float.compare(that.xDpi, xDpi) == 0
                     && Float.compare(that.yDpi, yDpi) == 0
                     && Float.compare(that.refreshRate, refreshRate) == 0
+                    && Float.compare(that.vsyncRate, vsyncRate) == 0
                     && appVsyncOffsetNanos == that.appVsyncOffsetNanos
                     && presentationDeadlineNanos == that.presentationDeadlineNanos
                     && Arrays.equals(supportedHdrTypes, that.supportedHdrTypes)
@@ -1835,8 +1843,9 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(id, width, height, xDpi, yDpi, refreshRate, appVsyncOffsetNanos,
-                    presentationDeadlineNanos, group, Arrays.hashCode(supportedHdrTypes));
+            return Objects.hash(id, width, height, xDpi, yDpi, refreshRate, vsyncRate,
+                    appVsyncOffsetNanos, presentationDeadlineNanos, group,
+                    Arrays.hashCode(supportedHdrTypes));
         }
     }
 
@@ -2785,10 +2794,22 @@
          * as a new transaction.
          */
         public void apply() {
-            apply(false);
+            apply(/*sync*/ false);
         }
 
         /**
+         * Applies the transaction as a one way binder call. This transaction will be applied out
+         * of order with other transactions that are applied synchronously. This method is not
+         * safe. It should only be used when the order does not matter.
+         *
+         * @hide
+         */
+        public void applyAsyncUnsafe() {
+            apply(/*sync*/ false, /*oneWay*/ true);
+        }
+
+
+        /**
          * Clear the transaction object, without applying it.
          *
          * @hide
@@ -2817,9 +2838,13 @@
          * @hide
          */
         public void apply(boolean sync) {
+            apply(sync, /*oneWay*/ false);
+        }
+
+        private void apply(boolean sync, boolean oneWay) {
             applyResizedSurfaces();
             notifyReparentedSurfaces();
-            nativeApplyTransaction(mNativeObject, sync);
+            nativeApplyTransaction(mNativeObject, sync, oneWay);
         }
 
         /**
@@ -4373,7 +4398,7 @@
         void applyGlobalTransaction(boolean sync) {
             applyResizedSurfaces();
             notifyReparentedSurfaces();
-            nativeApplyTransaction(mNativeObject, sync);
+            nativeApplyTransaction(mNativeObject, sync, /*oneWay*/ false);
         }
 
         @Override
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index effc127..57b19a8 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -407,7 +407,7 @@
     public @Nullable SurfacePackage getSurfacePackage() {
         if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {
             return new SurfacePackage(new SurfaceControl(mSurfaceControl, "getSurfacePackage"),
-                mAccessibilityEmbeddedConnection, getFocusGrantToken(), mRemoteInterface);
+                mAccessibilityEmbeddedConnection, getInputTransferToken(), mRemoteInterface);
         } else {
             return null;
         }
@@ -526,10 +526,12 @@
     }
 
     /**
+     * Returns an input token used which can be used to request focus on the embedded surface.
+     *
      * @hide
      */
-    public IBinder getFocusGrantToken() {
-        return mWm.getFocusGrantToken(getWindowToken().asBinder());
+    public IBinder getInputTransferToken() {
+        return mWm.getInputTransferToken(getWindowToken().asBinder());
     }
 
     private void addWindowToken(WindowManager.LayoutParams attrs) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cfde400..16318e0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12161,12 +12161,6 @@
      * a precision touch gesture in a small area in either the X or Y dimension, such as
      * an edge swipe or dragging a <code>SeekBar</code> thumb.</p>
      *
-     * <p>On Wear OS, these rects control where system-level swipe-to-dismiss gesture can start. If
-     * the attribute {@code android:windowSwipeToDismiss} has been set to {@code false}, the system
-     * will create an exclusion rect with size equal to the window frame size. In order words, the
-     * system swipe-to-dismiss will not apply, and the app must handle gestural input within itself.
-     * </p>
-     *
      * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the
      * exclusions it takes into account. The limit does not apply while the navigation
      * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index afa3157..e111dc8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -84,6 +84,7 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
+import static android.view.accessibility.Flags.forceInvertColor;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
 
@@ -154,6 +155,7 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.sysprop.DisplayProperties;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
@@ -1744,8 +1746,23 @@
         return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
     }
 
-    private void updateForceDarkMode() {
-        if (mAttachInfo.mThreadedRenderer == null) return;
+    /** Returns true if force dark should be enabled according to various settings */
+    @VisibleForTesting
+    public boolean isForceDarkEnabled() {
+        if (forceInvertColor()) {
+            boolean isForceInvertEnabled = Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
+                    /* def= */ 0,
+                    UserHandle.myUserId()) == 1;
+            // Force invert ignores all developer opt-outs.
+            // We also ignore dark theme, since the app developer can override the user's preference
+            // for dark mode in configuration.uiMode. Instead, we assume that the force invert
+            // setting will be enabled at the same time dark theme is in the Settings app.
+            if (isForceInvertEnabled) {
+                return true;
+            }
+        }
 
         boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
 
@@ -1757,8 +1774,12 @@
                     && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
             a.recycle();
         }
+        return useAutoDark;
+    }
 
-        if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) {
+    private void updateForceDarkMode() {
+        if (mAttachInfo.mThreadedRenderer == null) return;
+        if (mAttachInfo.mThreadedRenderer.setForceDark(isForceDarkEnabled())) {
             // TODO: Don't require regenerating all display lists to apply this setting
             invalidateWorld(mView);
         }
@@ -2211,9 +2232,7 @@
             mStopped = stopped;
             final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
             if (renderer != null) {
-                if (DEBUG_DRAW) {
-                    Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
-                }
+                if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
                 renderer.setStopped(mStopped);
             }
             if (!mStopped) {
@@ -3858,8 +3877,8 @@
                 mPendingTransitions.clear();
             }
 
-            handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mPendingTransaction,
-                    "view not visible");
+            handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
+                    mPendingTransaction, "view not visible");
         } else if (cancelAndRedraw) {
             mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
                 ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
@@ -3874,8 +3893,8 @@
                 mPendingTransitions.clear();
             }
             if (!performDraw(mActiveSurfaceSyncGroup)) {
-                handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mPendingTransaction,
-                        mLastPerformDrawSkippedReason);
+                handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
+                        mPendingTransaction, mLastPerformDrawSkippedReason);
             }
         }
 
@@ -4753,8 +4772,8 @@
             if (mSurfaceHolder != null && mSurface.isValid()) {
                 usingAsyncReport = true;
                 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> {
-                    handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction,
-                            "SurfaceHolder");
+                    handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null,
+                            pendingTransaction, "SurfaceHolder");
                 });
 
                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
@@ -4768,8 +4787,8 @@
         }
 
         if (!usingAsyncReport) {
-            handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction,
-                    "no async report");
+            handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null,
+                    pendingTransaction, "no async report");
         }
 
         if (mPerformContentCapture) {
@@ -4779,13 +4798,14 @@
     }
 
     private void handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup,
-            @Nullable Transaction pendingTransaction, String logReason) {
+            boolean hasPendingTransaction, @Nullable Transaction pendingTransaction,
+            String logReason) {
         if (surfaceSyncGroup != null) {
-            if (pendingTransaction != null) {
+            if (hasPendingTransaction && pendingTransaction != null) {
                 surfaceSyncGroup.addTransaction(pendingTransaction);
             }
             surfaceSyncGroup.markSyncReady();
-        } else if (pendingTransaction != null) {
+        } else if (hasPendingTransaction && pendingTransaction != null) {
             Trace.instant(Trace.TRACE_TAG_VIEW,
                     "Transaction not synced due to " + logReason + "-" + mTag);
             if (DEBUG_BLAST) {
@@ -5299,6 +5319,29 @@
     }
 
     /**
+     * Called from DecorView when gesture interception state has changed.
+     *
+     * @param intercepted If DecorView is intercepting touch events
+     */
+    public void updateDecorViewGestureInterception(boolean intercepted) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(
+                        MSG_DECOR_VIEW_GESTURE_INTERCEPTION,
+                        /* arg1= */ intercepted ? 1 : 0,
+                        /* arg2= */ 0));
+    }
+
+    void decorViewInterceptionChanged(boolean intercepted) {
+        if (mView != null) {
+            try {
+                mWindowSession.reportDecorViewGestureInterceptionChanged(mWindow, intercepted);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
      * Set the root-level system gesture exclusion rects. These are added to those provided by
      * the root's view hierarchy.
      */
@@ -5921,6 +5964,7 @@
     private static final int MSG_KEEP_CLEAR_RECTS_CHANGED = 35;
     private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36;
     private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37;
+    private static final int MSG_DECOR_VIEW_GESTURE_INTERCEPTION = 38;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -6199,6 +6243,9 @@
                 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: {
                     systemGestureExclusionChanged();
                 }   break;
+                case MSG_DECOR_VIEW_GESTURE_INTERCEPTION: {
+                    decorViewInterceptionChanged(/* intercepted= */ msg.arg1 == 1);
+                }   break;
                 case MSG_KEEP_CLEAR_RECTS_CHANGED: {
                     keepClearRectsChanged(/* accessibilityFocusRectChanged= */ msg.arg1 == 1);
                 }   break;
@@ -8558,10 +8605,6 @@
             mLastLayoutFrame.set(frame);
         }
 
-        if (mOnBackInvokedDispatcher.isSystemGestureExclusionNeeded()) {
-            setRootSystemGestureExclusionRects(List.of(frame));
-        }
-
         final WindowConfiguration winConfig = getCompatWindowConfiguration();
         mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop()
                 ? winConfig.getMaxBounds()
@@ -9006,8 +9049,8 @@
             mAdded = false;
             AnimationHandler.removeRequestor(this);
         }
-        handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mPendingTransaction,
-                "shutting down VRI");
+        handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
+                mPendingTransaction, "shutting down VRI");
         WindowManagerGlobal.getInstance().doRemoveView(this);
     }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e64274e..08f9c8c 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.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -1850,6 +1851,8 @@
                         to = "PHONE"),
                 @ViewDebug.IntToString(from = TYPE_SYSTEM_ALERT,
                         to = "SYSTEM_ALERT"),
+                @ViewDebug.IntToString(from = TYPE_KEYGUARD,
+                        to = "KEYGUARD"),
                 @ViewDebug.IntToString(from = TYPE_TOAST,
                         to = "TOAST"),
                 @ViewDebug.IntToString(from = TYPE_SYSTEM_OVERLAY,
@@ -1898,6 +1901,8 @@
                         to = "PRIVATE_PRESENTATION"),
                 @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION,
                         to = "VOICE_INTERACTION"),
+                @ViewDebug.IntToString(from = TYPE_ACCESSIBILITY_OVERLAY,
+                        to = "ACCESSIBILITY_OVERLAY"),
                 @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING,
                         to = "VOICE_INTERACTION_STARTING"),
                 @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER,
@@ -1907,7 +1912,13 @@
                 @ViewDebug.IntToString(from = TYPE_SCREENSHOT,
                         to = "SCREENSHOT"),
                 @ViewDebug.IntToString(from = TYPE_APPLICATION_OVERLAY,
-                        to = "APPLICATION_OVERLAY")
+                        to = "APPLICATION_OVERLAY"),
+                @ViewDebug.IntToString(from = TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
+                        to = "ACCESSIBILITY_MAGNIFICATION_OVERLAY"),
+                @ViewDebug.IntToString(from = TYPE_NOTIFICATION_SHADE,
+                        to = "NOTIFICATION_SHADE"),
+                @ViewDebug.IntToString(from = TYPE_STATUS_BAR_ADDITIONAL,
+                        to = "STATUS_BAR_ADDITIONAL")
         })
         @WindowType
         public int type;
@@ -5811,6 +5822,7 @@
      *
      * @hide
      */
+    @FlaggedApi("REPLACE_CONTENT_WITH_MIRROR")
     @TestApi
     @RequiresPermission(permission.ACCESS_SURFACE_FLINGER)
     default boolean replaceContentOnDisplayWithMirror(int displayId, @NonNull Window window) {
@@ -5826,6 +5838,7 @@
      *
      * @hide
      */
+    @FlaggedApi("REPLACE_CONTENT_WITH_MIRROR")
     @TestApi
     @RequiresPermission(permission.ACCESS_SURFACE_FLINGER)
     default boolean replaceContentOnDisplayWithSc(int displayId, @NonNull SurfaceControl sc) {
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 7d3d283..7c3b6ae 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -58,7 +58,7 @@
         SurfaceControl mLeash;
         Rect mFrame;
         Rect mAttachedFrame;
-        IBinder mFocusGrantToken;
+        IBinder mInputTransferToken;
 
         State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId, IWindow client,
                 SurfaceControl leash, Rect frame) {
@@ -89,7 +89,7 @@
     private final Configuration mConfiguration;
     private final IWindowSession mRealWm;
     private final IBinder mHostInputToken;
-    private final IBinder mFocusGrantToken = new Binder();
+    private final IBinder mInputTransferToken = new Binder();
     private InsetsState mInsetsState;
     private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();
     private final MergedConfiguration mTmpConfig = new MergedConfiguration();
@@ -109,17 +109,17 @@
         mConfiguration.setTo(configuration);
     }
 
-    IBinder getFocusGrantToken(IBinder window) {
+    IBinder getInputTransferToken(IBinder window) {
         synchronized (this) {
             // This can only happen if someone requested the focusGrantToken before setView was
             // called for the SCVH. In that case, use the root focusGrantToken since this will be
             // the same token sent to WMS for the root window once setView is called.
             if (mStateForWindow.isEmpty()) {
-                return mFocusGrantToken;
+                return mInputTransferToken;
             }
             State state = mStateForWindow.get(window);
             if (state != null) {
-                return state.mFocusGrantToken;
+                return state.mInputTransferToken;
             }
         }
 
@@ -207,9 +207,9 @@
             // Give the first window the mFocusGrantToken since that's the token the host can use
             // to give focus to the embedded.
             if (mStateForWindow.isEmpty()) {
-                state.mFocusGrantToken = mFocusGrantToken;
+                state.mInputTransferToken = mInputTransferToken;
             } else {
-                state.mFocusGrantToken = new Binder();
+                state.mInputTransferToken = new Binder();
             }
 
             mStateForWindow.put(window.asBinder(), state);
@@ -230,12 +230,13 @@
                             new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
                             window, mHostInputToken, attrs.flags, attrs.privateFlags,
                             attrs.inputFeatures, attrs.type,
-                            attrs.token, state.mFocusGrantToken, attrs.getTitle().toString(),
+                            attrs.token, state.mInputTransferToken, attrs.getTitle().toString(),
                             outInputChannel);
                 } else {
                     mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
                             attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token,
-                            state.mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
+                            state.mInputTransferToken, attrs.getTitle().toString(),
+                            outInputChannel);
                 }
                 state.mInputChannelToken =
                         outInputChannel != null ? outInputChannel.getToken() : null;
@@ -583,9 +584,13 @@
     }
 
     @Override
-    public void reportKeepClearAreasChanged(android.view.IWindow window, List<Rect> restrictedRects,
-            List<Rect> unrestrictedRects) {
-    }
+    public void reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted) {}
+
+    @Override
+    public void reportKeepClearAreasChanged(
+            android.view.IWindow window,
+            List<Rect> restrictedRects,
+            List<Rect> unrestrictedRects) {}
 
     @Override
     public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window,
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
new file mode 100644
index 0000000..85dadd4
--- /dev/null
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -0,0 +1,15 @@
+package: "android.view.accessibility"
+
+flag {
+    namespace: "accessibility"
+    name: "force_invert_color"
+    description: "Enable force force-dark for smart inversion and dark theme everywhere"
+    bug: "282821643"
+}
+
+flag {
+    namespace: "accessibility"
+    name: "allow_shortcut_chooser_on_lockscreen"
+    description: "Allows the a11y shortcut disambig dialog to appear on the lockscreen"
+    bug: "303871725"
+}
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index a07b62f..a76780d 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -108,11 +108,14 @@
      * @hide
      */
     @TestApi
+    @FlaggedApi(FLAG_EXPECTED_PRESENTATION_TIME_API)
     public static void lockAnimationClock(long vsyncMillis, long expectedPresentationTimeNanos) {
         AnimationState state = sAnimationState.get();
         state.animationClockLocked = true;
         state.currentVsyncTimeMillis = vsyncMillis;
-        state.mExpectedPresentationTimeNanos = expectedPresentationTimeNanos;
+        if (!expectedPresentationTimeApi()) {
+            state.mExpectedPresentationTimeNanos = expectedPresentationTimeNanos;
+        }
     }
 
     /**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 89fa83e..a40ff64 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,7 +16,6 @@
 
 package android.view.autofill;
 
-import static android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS;
 import static android.service.autofill.FillRequest.FLAG_IME_SHOWING;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
@@ -31,12 +30,10 @@
 import static android.view.autofill.Helper.toList;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
-import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -53,20 +50,17 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.Rect;
 import android.metrics.LogMaker;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.autofill.AutofillService;
-import android.service.autofill.FillCallback;
 import android.service.autofill.FillEventHistory;
+import android.service.autofill.Flags;
 import android.service.autofill.IFillCallback;
 import android.service.autofill.UserData;
 import android.text.TextUtils;
@@ -88,7 +82,6 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.AccessibilityWindowInfo;
-import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.CheckBox;
 import android.widget.DatePicker;
@@ -118,7 +111,6 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import sun.misc.Cleaner;
@@ -188,12 +180,6 @@
  * shows an autofill save UI if the value of savable views have changed. If the user selects the
  * option to Save, the current value of the views is then sent to the autofill service.
  *
- * <p>There is another choice for the application to provide it's datasets to the Autofill framework
- * by setting an {@link AutofillRequestCallback} through
- * {@link #setAutofillRequestCallback(Executor, AutofillRequestCallback)}. The application can use
- * its callback instead of the default {@link AutofillService}. See
- * {@link AutofillRequestCallback} for more details.
- *
  * <h3 id="additional-notes">Additional notes</h3>
  *
  * <p>It is safe to call <code>AutofillManager</code> methods from any thread.
@@ -277,6 +263,12 @@
             "android.view.autofill.extra.CLIENT_STATE";
 
     /**
+     * @hide
+     */
+    public static final String EXTRA_AUTH_STATE =
+            "android.view.autofill.extra.AUTH_STATE";
+
+    /**
      * Intent extra: the {@link android.view.inputmethod.InlineSuggestionsRequest} in the
      * autofill request.
      *
@@ -327,7 +319,6 @@
     /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
     /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
     /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8;
-    /** @hide */ public static final int FLAG_ENABLED_CLIENT_SUGGESTIONS = 0x20;
 
     // NOTE: flag below is used by the session start receiver only, hence it can have values above
     /** @hide */ public static final int RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
@@ -428,6 +419,14 @@
     public static final int STATE_UNKNOWN_FAILED = 6;
 
     /**
+     * Same as {@link #STATE_ACTIVE}, but when pending authentication after
+     * {@link AutofillManagerClient#authenticate(int, int, IntentSender, Intent, boolean)}
+     *
+     * @hide
+     */
+    public static final int STATE_PENDING_AUTHENTICATION = 7;
+
+    /**
      * Timeout in ms for calls to the field classification service.
      * @hide
      */
@@ -661,11 +660,6 @@
     @GuardedBy("mLock")
     private boolean mEnabledForAugmentedAutofillOnly;
 
-    @GuardedBy("mLock")
-    @Nullable private AutofillRequestCallback mAutofillRequestCallback;
-    @GuardedBy("mLock")
-    @Nullable private Executor mRequestCallbackExecutor;
-
     private boolean mScreenHasCredmanField;
 
     /**
@@ -731,6 +725,10 @@
     // Indicate whether WebView should always be included in the assist structure
     private boolean mShouldAlwaysIncludeWebviewInAssistStructure;
 
+    // Controls logic around apps changing some properties of their views when activity loses
+    // focus due to autofill showing biometric activity, password manager, or password breach check.
+    private boolean mRelayoutFix;
+
     // Indicates whether called the showAutofillDialog() method.
     private boolean mShowAutofillDialogCalled = false;
 
@@ -952,6 +950,8 @@
 
         mShouldAlwaysIncludeWebviewInAssistStructure =
                 AutofillFeatureFlags.shouldAlwaysIncludeWebviewInAssistStructure();
+
+        mRelayoutFix = Flags.relayout();
     }
 
     /**
@@ -1715,7 +1715,13 @@
         synchronized (mLock) {
             if (mForAugmentedAutofillOnly) {
                 if (sVerbose) {
-                    Log.v(TAG,  "notifyViewVisibilityChanged(): ignoring on augmented only mode");
+                    Log.v(TAG, "notifyViewVisibilityChanged(): ignoring on augmented only mode");
+                }
+                return;
+            }
+            if (mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION) {
+                if (sVerbose) {
+                    Log.v(TAG, "notifyViewVisibilityChanged(): ignoring in auth pending mode");
                 }
                 return;
             }
@@ -2342,6 +2348,7 @@
             if (!isActiveLocked()) {
                 return;
             }
+            mState = STATE_ACTIVE;
             // If authenticate activity closes itself during onCreate(), there is no onStop/onStart
             // of app activity.  We enforce enter event to re-show fill ui in such case.
             // CTS example:
@@ -2406,38 +2413,6 @@
         return new AutofillId(parent.getAutofillViewId(), virtualId);
     }
 
-    /**
-     * Sets the client's suggestions callback for autofill.
-     *
-     * @see AutofillRequestCallback
-     *
-     * @param executor specifies the thread upon which the callbacks will be invoked.
-     * @param callback which handles autofill request to provide client's suggestions.
-     */
-    @RequiresPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
-    public void setAutofillRequestCallback(@NonNull @CallbackExecutor Executor executor,
-            @NonNull AutofillRequestCallback callback) {
-        if (mContext.checkSelfPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires PROVIDE_OWN_AUTOFILL_SUGGESTIONS permission!");
-        }
-
-        synchronized (mLock) {
-            mRequestCallbackExecutor = executor;
-            mAutofillRequestCallback = callback;
-        }
-    }
-
-    /**
-     * clears the client's suggestions callback for autofill.
-     */
-    public void clearAutofillRequestCallback() {
-        synchronized (mLock) {
-            mRequestCallbackExecutor = null;
-            mAutofillRequestCallback = null;
-        }
-    }
-
     @GuardedBy("mLock")
     private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
             @NonNull AutofillValue value, int flags) {
@@ -2498,13 +2473,6 @@
                 }
             }
 
-            if (mAutofillRequestCallback != null) {
-                if (sDebug) {
-                    Log.d(TAG, "startSession with the client suggestions provider");
-                }
-                flags |= FLAG_ENABLED_CLIENT_SUGGESTIONS;
-            }
-
             mService.startSession(client.autofillClientGetActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                     mCallback != null, flags, clientActivity,
@@ -2830,6 +2798,9 @@
             Intent fillInIntent, boolean authenticateInline) {
         synchronized (mLock) {
             if (sessionId == mSessionId) {
+                if (mRelayoutFix) {
+                    mState = STATE_PENDING_AUTHENTICATION;
+                }
                 final AutofillClient client = getClient();
                 if (client != null) {
                     // clear mOnInvisibleCalled and we will see if receive onInvisibleForAutofill()
@@ -2859,28 +2830,6 @@
         }
     }
 
-    private void onFillRequest(InlineSuggestionsRequest request,
-            CancellationSignal cancellationSignal, FillCallback callback) {
-        final AutofillRequestCallback autofillRequestCallback;
-        final Executor executor;
-        synchronized (mLock) {
-            autofillRequestCallback = mAutofillRequestCallback;
-            executor = mRequestCallbackExecutor;
-        }
-        if (autofillRequestCallback != null && executor != null) {
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                executor.execute(() ->
-                        autofillRequestCallback.onFillRequest(
-                                request, cancellationSignal, callback));
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        } else {
-            callback.onSuccess(null);
-        }
-    }
-
     /** @hide */
     public static final int SET_STATE_FLAG_ENABLED = 0x01;
     /** @hide */
@@ -3563,6 +3512,8 @@
                 return "UNKNOWN";
             case STATE_ACTIVE:
                 return "ACTIVE";
+            case STATE_PENDING_AUTHENTICATION:
+                return "PENDING_AUTHENTICATION";
             case STATE_FINISHED:
                 return "FINISHED";
             case STATE_SHOWING_SAVE_UI:
@@ -3592,7 +3543,12 @@
 
     @GuardedBy("mLock")
     private boolean isActiveLocked() {
-        return mState == STATE_ACTIVE;
+        return mState == STATE_ACTIVE || isPendingAuthenticationLocked();
+    }
+
+    @GuardedBy("mLock")
+    private boolean isPendingAuthenticationLocked() {
+        return mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION;
     }
 
     @GuardedBy("mLock")
@@ -4457,23 +4413,6 @@
         }
 
         @Override
-        public void requestFillFromClient(int id, InlineSuggestionsRequest request,
-                IFillCallback callback) {
-            final AutofillManager afm = mAfm.get();
-            if (afm != null) {
-                ICancellationSignal transport = CancellationSignal.createTransport();
-                try {
-                    callback.onCancellable(transport);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Error requesting a cancellation", e);
-                }
-
-                afm.onFillRequest(request, CancellationSignal.fromTransport(transport),
-                        new FillCallback(callback, id));
-            }
-        }
-
-        @Override
         public void notifyFillDialogTriggerIds(List<AutofillId> ids) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java
deleted file mode 100644
index e632a58..0000000
--- a/core/java/android/view/autofill/AutofillRequestCallback.java
+++ /dev/null
@@ -1,72 +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.view.autofill;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.CancellationSignal;
-import android.service.autofill.FillCallback;
-import android.view.inputmethod.InlineSuggestionsRequest;
-
-/**
- * <p>This class is used to provide some input suggestions to the Autofill framework.
- *
- * <P>When the user is requested to input something, Autofill will try to query input suggestions
- * for the user choosing. If the application want to provide some internal input suggestions,
- * implements this callback and register via
- * {@link AutofillManager#setAutofillRequestCallback(java.util.concurrent.Executor,
- * AutofillRequestCallback)}. Autofill will callback the
- * {@link #onFillRequest(InlineSuggestionsRequest, CancellationSignal, FillCallback)} to request
- * input suggestions.
- *
- * <P>To make sure the callback to take effect, must register before the autofill session starts.
- * If the autofill session is started, calls {@link AutofillManager#cancel()} to finish current
- * session, and then the callback will be used at the next restarted session.
- *
- * <P>To create a {@link android.service.autofill.FillResponse}, application should fetch
- * {@link AutofillId}s from its view structure. Below is an example:
- * <pre class="prettyprint">
- * AutofillId usernameId = findViewById(R.id.username).getAutofillId();
- * AutofillId passwordId = findViewById(R.id.password).getAutofillId();
- * </pre>
- * To learn more about creating a {@link android.service.autofill.FillResponse}, read
- * <a href="/guide/topics/text/autofill-services#fill">Fill out client views</a>.
- *
- * <P>To fallback to the default {@link android.service.autofill.AutofillService}, just respond
- * a null of the {@link android.service.autofill.FillResponse}. And then Autofill will do a fill
- * request with the default {@link android.service.autofill.AutofillService}. Or clear the callback
- * from {@link AutofillManager} via {@link AutofillManager#clearAutofillRequestCallback()}. If the
- * client would like to keep no suggestions for the field, respond with an empty
- * {@link android.service.autofill.FillResponse} which has no dataset.
- *
- * <P>IMPORTANT: This should not be used for displaying anything other than input suggestions, or
- * the keyboard may choose to block your app from the inline strip.
- */
-public interface AutofillRequestCallback {
-    /**
-     * Called by the Android system to decide if a screen can be autofilled by the callback.
-     *
-     * @param inlineSuggestionsRequest the {@link InlineSuggestionsRequest request} to handle if
-     *     currently inline suggestions are supported and can be displayed.
-     * @param cancellationSignal signal for observing cancellation requests. The system will use
-     *     this to notify you that the fill result is no longer needed and you should stop
-     *     handling this fill request in order to save resources.
-     * @param callback object used to notify the result of the request.
-     */
-    void onFillRequest(@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
-            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
-}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 6e13097..917a974 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -24,11 +24,9 @@
 import android.content.IntentSender;
 import android.graphics.Rect;
 import android.os.IBinder;
-import android.service.autofill.IFillCallback;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutofillWindowPresenter;
-import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.KeyEvent;
 
 import com.android.internal.os.IResultReceiver;
@@ -149,12 +147,6 @@
    void requestShowSoftInput(in AutofillId id);
 
     /**
-     * Requests to determine if a screen can be autofilled by the client app.
-     */
-    void requestFillFromClient(int id, in InlineSuggestionsRequest request,
-            in IFillCallback callback);
-
-    /**
      * Notifies autofill ids that require to show the fill dialog.
      */
     void notifyFillDialogTriggerIds(in List<AutofillId> ids);
diff --git a/core/java/android/view/flags/variable_refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
similarity index 78%
rename from core/java/android/view/flags/variable_refresh_rate_flags.aconfig
rename to core/java/android/view/flags/refresh_rate_flags.aconfig
index 13a6f8d..56b5fac 100644
--- a/core/java/android/view/flags/variable_refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -19,4 +19,11 @@
     namespace: "toolkit"
     description: "Feature flag for using expected presentation time of the Choreographer"
     bug: "278730197"
+}
+
+flag {
+  name: "set_frame_rate_callback"
+  namespace: "core_graphics"
+  description: "Enable the `setFrameRate` callback"
+  bug: "299946220"
 }
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 70279cc..c83dfe8 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -111,22 +111,6 @@
     private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
 
     /**
-     * Whether the IME supports inline suggestions from the default Autofill service that
-     * provides the input view.
-     *
-     * Note: The default value is {@code true}.
-     */
-    private boolean mServiceSupported;
-
-    /**
-     * Whether the IME supports inline suggestions from the application that provides the
-     * input view.
-     *
-     * Note: The default value is {@code true}.
-     */
-    private boolean mClientSupported;
-
-    /**
      * @hide
      * @see {@link #mHostInputToken}.
      */
@@ -220,14 +204,6 @@
         return Bundle.EMPTY;
     }
 
-    private static boolean defaultServiceSupported() {
-        return true;
-    }
-
-    private static boolean defaultClientSupported() {
-        return true;
-    }
-
     /** @hide */
     abstract static class BaseBuilder {
         abstract Builder setInlinePresentationSpecs(
@@ -240,25 +216,13 @@
         abstract Builder setHostDisplayId(int value);
     }
 
-    /** @hide */
-    public boolean isServiceSupported() {
-        return mServiceSupported;
-    }
-
-    /** @hide */
-    public boolean isClientSupported() {
-        return mClientSupported;
-    }
-
-
-
-    // Code below generated by codegen v1.0.22.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+    // $ codegen $ANDROID_BUILD_TOP/./frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -274,9 +238,7 @@
             @NonNull Bundle extras,
             @Nullable IBinder hostInputToken,
             int hostDisplayId,
-            @Nullable InlinePresentationSpec inlineTooltipPresentationSpec,
-            boolean serviceSupported,
-            boolean clientSupported) {
+            @Nullable InlinePresentationSpec inlineTooltipPresentationSpec) {
         this.mMaxSuggestionCount = maxSuggestionCount;
         this.mInlinePresentationSpecs = inlinePresentationSpecs;
         com.android.internal.util.AnnotationValidations.validate(
@@ -293,8 +255,6 @@
         this.mHostInputToken = hostInputToken;
         this.mHostDisplayId = hostDisplayId;
         this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
-        this.mServiceSupported = serviceSupported;
-        this.mClientSupported = clientSupported;
 
         onConstructed();
     }
@@ -378,9 +338,7 @@
     }
 
     /**
-     * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
-     *
-     * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)
+     * Specifies the UI specification for the inline suggestion tooltip in the response.
      */
     @DataClass.Generated.Member
     public @Nullable InlinePresentationSpec getInlineTooltipPresentationSpec() {
@@ -401,9 +359,7 @@
                 "extras = " + mExtras + ", " +
                 "hostInputToken = " + mHostInputToken + ", " +
                 "hostDisplayId = " + mHostDisplayId + ", " +
-                "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec + ", " +
-                "serviceSupported = " + mServiceSupported + ", " +
-                "clientSupported = " + mClientSupported +
+                "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec +
         " }";
     }
 
@@ -427,9 +383,7 @@
                 && extrasEquals(that.mExtras)
                 && java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
                 && mHostDisplayId == that.mHostDisplayId
-                && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec)
-                && mServiceSupported == that.mServiceSupported
-                && mClientSupported == that.mClientSupported;
+                && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec);
     }
 
     @Override
@@ -447,8 +401,6 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
         _hash = 31 * _hash + mHostDisplayId;
         _hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipPresentationSpec);
-        _hash = 31 * _hash + Boolean.hashCode(mServiceSupported);
-        _hash = 31 * _hash + Boolean.hashCode(mClientSupported);
         return _hash;
     }
 
@@ -459,8 +411,6 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         int flg = 0;
-        if (mServiceSupported) flg |= 0x100;
-        if (mClientSupported) flg |= 0x200;
         if (mHostInputToken != null) flg |= 0x20;
         if (mInlineTooltipPresentationSpec != null) flg |= 0x80;
         dest.writeInt(flg);
@@ -486,11 +436,9 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         int flg = in.readInt();
-        boolean serviceSupported = (flg & 0x100) != 0;
-        boolean clientSupported = (flg & 0x200) != 0;
         int maxSuggestionCount = in.readInt();
         List<InlinePresentationSpec> inlinePresentationSpecs = new ArrayList<>();
-        in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader(), android.widget.inline.InlinePresentationSpec.class);
+        in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader());
         String hostPackageName = in.readString();
         LocaleList supportedLocales = (LocaleList) in.readTypedObject(LocaleList.CREATOR);
         Bundle extras = in.readBundle();
@@ -514,8 +462,6 @@
         this.mHostInputToken = hostInputToken;
         this.mHostDisplayId = hostDisplayId;
         this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
-        this.mServiceSupported = serviceSupported;
-        this.mClientSupported = clientSupported;
 
         onConstructed();
     }
@@ -549,8 +495,6 @@
         private @Nullable IBinder mHostInputToken;
         private int mHostDisplayId;
         private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
-        private boolean mServiceSupported;
-        private boolean mClientSupported;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -683,9 +627,7 @@
         }
 
         /**
-         * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
-         *
-         * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)s
+         * Specifies the UI specification for the inline suggestion tooltip in the response.
          */
         @DataClass.Generated.Member
         public @NonNull Builder setInlineTooltipPresentationSpec(@NonNull InlinePresentationSpec value) {
@@ -695,38 +637,10 @@
             return this;
         }
 
-        /**
-         * Whether the IME supports inline suggestions from the default Autofill service that
-         * provides the input view.
-         *
-         * Note: The default value is {@code true}.
-         */
-        @DataClass.Generated.Member
-        public @NonNull Builder setServiceSupported(boolean value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x100;
-            mServiceSupported = value;
-            return this;
-        }
-
-        /**
-         * Whether the IME supports inline suggestions from the application that provides the
-         * input view.
-         *
-         * Note: The default value is {@code true}.
-         */
-        @DataClass.Generated.Member
-        public @NonNull Builder setClientSupported(boolean value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x200;
-            mClientSupported = value;
-            return this;
-        }
-
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull InlineSuggestionsRequest build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x400; // Mark builder used
+            mBuilderFieldsSet |= 0x100; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mMaxSuggestionCount = defaultMaxSuggestionCount();
@@ -749,12 +663,6 @@
             if ((mBuilderFieldsSet & 0x80) == 0) {
                 mInlineTooltipPresentationSpec = defaultInlineTooltipPresentationSpec();
             }
-            if ((mBuilderFieldsSet & 0x100) == 0) {
-                mServiceSupported = defaultServiceSupported();
-            }
-            if ((mBuilderFieldsSet & 0x200) == 0) {
-                mClientSupported = defaultClientSupported();
-            }
             InlineSuggestionsRequest o = new InlineSuggestionsRequest(
                     mMaxSuggestionCount,
                     mInlinePresentationSpecs,
@@ -763,14 +671,12 @@
                     mExtras,
                     mHostInputToken,
                     mHostDisplayId,
-                    mInlineTooltipPresentationSpec,
-                    mServiceSupported,
-                    mClientSupported);
+                    mInlineTooltipPresentationSpec);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x400) != 0) {
+            if ((mBuilderFieldsSet & 0x100) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -778,10 +684,10 @@
     }
 
     @DataClass.Generated(
-            time = 1615798784918L,
-            codegenVersion = "1.0.22",
+            time = 1696889841006L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
-            inputSignatures = "public static final  int SUGGESTION_COUNT_UNLIMITED\nprivate final  int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate  int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate  boolean mServiceSupported\nprivate  boolean mClientSupported\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic  void setHostInputToken(android.os.IBinder)\nprivate  boolean extrasEquals(android.os.Bundle)\nprivate  void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic  void setHostDisplayId(int)\nprivate  void onConstructed()\npublic  void filterContentTypes()\nprivate static  int defaultMaxSuggestionCount()\nprivate static  java.lang.String defaultHostPackageName()\nprivate static  android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static  android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nprivate static  boolean defaultServiceSupported()\nprivate static  boolean defaultClientSupported()\npublic  boolean isServiceSupported()\npublic  boolean isClientSupported()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+            inputSignatures = "public static final  int SUGGESTION_COUNT_UNLIMITED\nprivate final  int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate  int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic  void setHostInputToken(android.os.IBinder)\nprivate  boolean extrasEquals(android.os.Bundle)\nprivate  void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic  void setHostDisplayId(int)\nprivate  void onConstructed()\npublic  void filterContentTypes()\nprivate static  int defaultMaxSuggestionCount()\nprivate static  java.lang.String defaultHostPackageName()\nprivate static  android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static  android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index 195565c..33db671 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -551,8 +551,8 @@
          * Sets the entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}.
          * <p>
          * Supported types:
-         * <p>See {@link TextClassifier.EntityType}
-         * <p>See {@link ConversationAction.ActionType}
+         * <p>See {@link TextClassifier} types
+         * <p>See {@link ConversationAction} types
          * <p>See {@link ULocale#toLanguageTag()}
          */
         @NonNull
diff --git a/core/java/android/view/translation/TranslationCapability.java b/core/java/android/view/translation/TranslationCapability.java
index b7e13dd..52760f7 100644
--- a/core/java/android/view/translation/TranslationCapability.java
+++ b/core/java/android/view/translation/TranslationCapability.java
@@ -207,7 +207,7 @@
 
     /**
      * Translation flags for settings that are supported by the
-     * {@link android.service.translation.TranslationService} between the {@link TranslationSpec}s
+     * translation service between the {@link TranslationSpec}s
      * provided in this capability.
      */
     @DataClass.Generated.Member
diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java
index 5aad823..99544e8 100644
--- a/core/java/android/view/translation/TranslationManager.java
+++ b/core/java/android/view/translation/TranslationManager.java
@@ -56,7 +56,7 @@
  * translation framework.
  *
  * <p>The TranslationManager manages {@link Translator}s and help bridge client calls to
- * the server {@link android.service.translation.TranslationService} </p>
+ * the server translation service </p>
  */
 @SystemService(Context.TRANSLATION_MANAGER_SERVICE)
 public final class TranslationManager {
diff --git a/core/java/android/view/translation/TranslationRequest.java b/core/java/android/view/translation/TranslationRequest.java
index 027edc2..ff11ffa 100644
--- a/core/java/android/view/translation/TranslationRequest.java
+++ b/core/java/android/view/translation/TranslationRequest.java
@@ -27,7 +27,7 @@
 import java.util.List;
 
 /**
- * Translation request sent to the {@link android.service.translation.TranslationService} by the
+ * Translation request sent to the translation service by the
  * {@link android.view.translation.Translator} which contains the text to be translated.
  */
 @DataClass(genToString = true, genHiddenConstDefs = true, genBuilder = true)
diff --git a/core/java/android/view/translation/TranslationResponse.java b/core/java/android/view/translation/TranslationResponse.java
index b77f2e2..3362fc0 100644
--- a/core/java/android/view/translation/TranslationResponse.java
+++ b/core/java/android/view/translation/TranslationResponse.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.service.translation.TranslationService;
 import android.util.SparseArray;
 
 import com.android.internal.util.DataClass;
@@ -30,17 +29,17 @@
 import java.util.Objects;
 
 /**
- * Response from the {@link TranslationService}, which contains the translated result.
+ * Response from the translation service, which contains the translated result.
  */
 @DataClass(genBuilder = true, genToString = true, genHiddenConstDefs = true)
 public final class TranslationResponse implements Parcelable {
 
     /**
-     * The {@link TranslationService} was successful in translating.
+     * The translation service was successful in translating.
      */
     public static final int TRANSLATION_STATUS_SUCCESS = 0;
     /**
-     * The {@link TranslationService} returned unknown translation result.
+     * The translation service returned unknown translation result.
      */
     public static final int TRANSLATION_STATUS_UNKNOWN_ERROR = 1;
     /**
diff --git a/core/java/android/view/translation/TranslationResponseValue.java b/core/java/android/view/translation/TranslationResponseValue.java
index 9dff2d5..18a240d 100644
--- a/core/java/android/view/translation/TranslationResponseValue.java
+++ b/core/java/android/view/translation/TranslationResponseValue.java
@@ -27,7 +27,7 @@
 import java.util.Objects;
 
 /**
- * A translated response value from {@link android.service.translation.TranslationService}.
+ * A translated response value from translation service.
  */
 @DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true,
         genHiddenConstDefs = true)
diff --git a/core/java/android/view/translation/ViewTranslationRequest.java b/core/java/android/view/translation/ViewTranslationRequest.java
index a41749a..54b8ac2 100644
--- a/core/java/android/view/translation/ViewTranslationRequest.java
+++ b/core/java/android/view/translation/ViewTranslationRequest.java
@@ -33,7 +33,7 @@
 
 /**
  * Wrapper class representing a translation request associated with a {@link android.view.View} to
- * be used by {@link android.service.translation.TranslationService}.
+ * be used by translation service.
  */
 @DataClass(genBuilder = false, genToString = true, genEqualsHashCode = true, genGetters = false,
         genHiddenConstructor = true, genHiddenConstDefs = true)
diff --git a/core/java/android/view/translation/ViewTranslationResponse.java b/core/java/android/view/translation/ViewTranslationResponse.java
index d993114..134ff5a 100644
--- a/core/java/android/view/translation/ViewTranslationResponse.java
+++ b/core/java/android/view/translation/ViewTranslationResponse.java
@@ -33,7 +33,7 @@
 
 /**
  * Wrapper class representing a translation response associated with a {@link android.view.View} to
- * be used by {@link android.service.translation.TranslationService}.
+ * be used by translation service.
  */
 @DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true, genGetters = false)
 public final class ViewTranslationResponse implements Parcelable {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 26ceea6..1fdd1a5 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -80,6 +80,7 @@
 import android.view.autofill.AutofillId;
 import android.view.contentcapture.ContentCaptureManager;
 import android.view.contentcapture.ContentCaptureSession;
+import android.view.flags.Flags;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
@@ -92,7 +93,6 @@
 import android.view.inputmethod.SurroundingText;
 import android.view.inspector.InspectableProperty;
 import android.view.inspector.InspectableProperty.EnumEntry;
-import android.widget.flags.Flags;
 import android.widget.RemoteViews.InteractionHandler;
 
 import com.android.internal.R;
@@ -4518,7 +4518,7 @@
                     final int overscrollMode = getOverScrollMode();
 
                     if (!trackMotionScroll(delta, delta)) {
-                        if (Flags.platformWidgetHapticScrollFeedback()) {
+                        if (Flags.scrollFeedbackApi()) {
                             initHapticScrollFeedbackProviderIfNotExists();
                             mHapticScrollFeedbackProvider.onScrollProgress(
                                     event.getDeviceId(), event.getSource(), axis, delta);
@@ -4534,7 +4534,7 @@
                         float overscroll = (delta - (motionViewRealTop - motionViewPrevTop))
                                 / ((float) getHeight());
                         boolean hitTopLimit = delta > 0;
-                        if (Flags.platformWidgetHapticScrollFeedback()) {
+                        if (Flags.scrollFeedbackApi()) {
                             initHapticScrollFeedbackProviderIfNotExists();
                             mHapticScrollFeedbackProvider.onScrollLimit(
                                     event.getDeviceId(), event.getSource(), axis,
diff --git a/core/java/android/widget/DifferentialMotionFlingHelper.java b/core/java/android/widget/DifferentialMotionFlingHelper.java
index 95d24ec..ef01c3b 100644
--- a/core/java/android/widget/DifferentialMotionFlingHelper.java
+++ b/core/java/android/widget/DifferentialMotionFlingHelper.java
@@ -21,6 +21,8 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
+import android.widget.flags.FeatureFlags;
+import android.widget.flags.FeatureFlagsImpl;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -50,6 +52,8 @@
     private final FlingVelocityThresholdCalculator mVelocityThresholdCalculator;
     private final DifferentialVelocityProvider mVelocityProvider;
 
+    private final FeatureFlags mWidgetFeatureFlags;
+
     @Nullable private VelocityTracker mVelocityTracker;
 
     private float mLastFlingVelocity;
@@ -134,7 +138,8 @@
         this(context,
                 target,
                 DifferentialMotionFlingHelper::calculateFlingVelocityThresholds,
-                DifferentialMotionFlingHelper::getCurrentVelocity);
+                DifferentialMotionFlingHelper::getCurrentVelocity,
+                /* widgetFeatureFlags= */ new FeatureFlagsImpl());
     }
 
     @VisibleForTesting
@@ -142,11 +147,13 @@
             Context context,
             DifferentialMotionFlingTarget target,
             FlingVelocityThresholdCalculator velocityThresholdCalculator,
-            DifferentialVelocityProvider velocityProvider) {
+            DifferentialVelocityProvider velocityProvider,
+            FeatureFlags widgetFeatureFlags) {
         mContext = context;
         mTarget = target;
         mVelocityThresholdCalculator = velocityThresholdCalculator;
         mVelocityProvider = velocityProvider;
+        mWidgetFeatureFlags = widgetFeatureFlags;
     }
 
     /**
@@ -156,6 +163,9 @@
      * @param axis the axis being processed by the target View.
      */
     public void onMotionEvent(MotionEvent event, int axis) {
+        if (!mWidgetFeatureFlags.enablePlatformWidgetDifferentialMotionFling()) {
+            return;
+        }
         boolean flingParamsChanged = calculateFlingVelocityThresholds(event, axis);
         if (mFlingVelocityThresholds[0] == Integer.MAX_VALUE) {
             // Integer.MAX_VALUE means that the device does not support fling for the current
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 79acfbb..103725d 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -638,9 +638,13 @@
      * Base class for all actions that can be performed on an
      * inflated view.
      *
-     *  SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
+     * SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
      */
     private abstract static class Action implements Parcelable {
+        @IdRes
+        @UnsupportedAppUsage
+        int mViewId;
+
         public abstract void apply(View root, ViewGroup rootParent, ActionApplyParams params)
                 throws ActionException;
 
@@ -664,7 +668,7 @@
         public abstract int getActionTag();
 
         public String getUniqueKey() {
-            return (getActionTag() + "_" + viewId);
+            return (getActionTag() + "_" + mViewId);
         }
 
         /**
@@ -684,16 +688,12 @@
         public void visitUris(@NonNull Consumer<Uri> visitor) {
             // Nothing to visit by default
         }
-
-        @IdRes
-        @UnsupportedAppUsage
-        int viewId;
     }
 
     /**
      * Action class used during async inflation of RemoteViews. Subclasses are not parcelable.
      */
-    private static abstract class RuntimeAction extends Action {
+    private abstract static class RuntimeAction extends Action {
         @Override
         public final int getActionTag() {
             return 0;
@@ -796,15 +796,16 @@
             for (int i = 0; i < mActions.size(); i++) {
                 Action action = mActions.get(i);
                 if (action instanceof SetRemoteCollectionItemListAdapterAction itemsAction
-                        && itemsAction.viewId == viewId
+                        && itemsAction.mViewId == viewId
                         && itemsAction.mServiceIntent != null) {
-                    mActions.set(i, new SetRemoteCollectionItemListAdapterAction(itemsAction.viewId,
-                            itemsAction.mServiceIntent));
+                    mActions.set(i,
+                            new SetRemoteCollectionItemListAdapterAction(itemsAction.mViewId,
+                                    itemsAction.mServiceIntent));
                     isActionReplaced = true;
                 } else if (action instanceof SetRemoteViewsAdapterIntent intentAction
-                        && intentAction.viewId == viewId) {
+                        && intentAction.mViewId == viewId) {
                     mActions.set(i, new SetRemoteCollectionItemListAdapterAction(
-                            intentAction.viewId, intentAction.intent));
+                            intentAction.mViewId, intentAction.mIntent));
                     isActionReplaced = true;
                 } else if (action instanceof ViewGroupActionAdd groupAction
                         && groupAction.mNestedViews != null) {
@@ -838,7 +839,7 @@
                 if ((action instanceof SetRemoteCollectionItemListAdapterAction itemsAction
                         && itemsAction.mServiceIntent != null)
                         || (action instanceof SetRemoteViewsAdapterIntent intentAction
-                                && intentAction.intent != null)
+                                && intentAction.mIntent != null)
                         || (action instanceof ViewGroupActionAdd groupAction
                                 && groupAction.mNestedViews != null
                                 && groupAction.mNestedViews.hasLegacyLists())) {
@@ -856,11 +857,7 @@
         if (mLandscape != null && mLandscape.hasLegacyLists()) {
             return true;
         }
-        if (mPortrait != null && mPortrait.hasLegacyLists()) {
-            return true;
-        }
-
-        return false;
+        return mPortrait != null && mPortrait.hasLegacyLists();
     }
 
     private static void visitIconUri(Icon icon, @NonNull Consumer<Uri> visitor) {
@@ -913,31 +910,31 @@
     }
 
     private static class SetEmptyView extends Action {
-        int emptyViewId;
+        int mEmptyViewId;
 
         SetEmptyView(@IdRes int viewId, @IdRes int emptyViewId) {
-            this.viewId = viewId;
-            this.emptyViewId = emptyViewId;
+            this.mViewId = viewId;
+            this.mEmptyViewId = emptyViewId;
         }
 
         SetEmptyView(Parcel in) {
-            this.viewId = in.readInt();
-            this.emptyViewId = in.readInt();
+            this.mViewId = in.readInt();
+            this.mEmptyViewId = in.readInt();
         }
 
         public void writeToParcel(Parcel out, int flags) {
-            out.writeInt(this.viewId);
-            out.writeInt(this.emptyViewId);
+            out.writeInt(this.mViewId);
+            out.writeInt(this.mEmptyViewId);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View view = root.findViewById(viewId);
+            final View view = root.findViewById(mViewId);
             if (!(view instanceof AdapterView<?>)) return;
 
             AdapterView<?> adapterView = (AdapterView<?>) view;
 
-            final View emptyView = root.findViewById(emptyViewId);
+            final View emptyView = root.findViewById(mEmptyViewId);
             if (emptyView == null) return;
 
             adapterView.setEmptyView(emptyView);
@@ -950,24 +947,27 @@
     }
 
     private static class SetPendingIntentTemplate extends Action {
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+        PendingIntent mPendingIntentTemplate;
+
         public SetPendingIntentTemplate(@IdRes int id, PendingIntent pendingIntentTemplate) {
-            this.viewId = id;
-            this.pendingIntentTemplate = pendingIntentTemplate;
+            this.mViewId = id;
+            this.mPendingIntentTemplate = pendingIntentTemplate;
         }
 
         public SetPendingIntentTemplate(Parcel parcel) {
-            viewId = parcel.readInt();
-            pendingIntentTemplate = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
+            mViewId = parcel.readInt();
+            mPendingIntentTemplate = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            PendingIntent.writePendingIntentOrNullToParcel(pendingIntentTemplate, dest);
+            dest.writeInt(mViewId);
+            PendingIntent.writePendingIntentOrNullToParcel(mPendingIntentTemplate, dest);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             // If the view isn't an AdapterView, setting a PendingIntent template doesn't make sense
@@ -981,10 +981,10 @@
                     }
                 };
                 av.setOnItemClickListener(listener);
-                av.setTag(pendingIntentTemplate);
+                av.setTag(mPendingIntentTemplate);
             } else {
                 Log.e(LOG_TAG, "Cannot setPendingIntentTemplate on a view which is not" +
-                        "an AdapterView (id: " + viewId + ")");
+                        "an AdapterView (id: " + mViewId + ")");
                 return;
             }
         }
@@ -1015,65 +1015,65 @@
         public int getActionTag() {
             return SET_PENDING_INTENT_TEMPLATE_TAG;
         }
-
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        PendingIntent pendingIntentTemplate;
     }
 
     private static class SetRemoteViewsAdapterList extends Action {
+        int mViewTypeCount;
+        ArrayList<RemoteViews> mList;
+
         public SetRemoteViewsAdapterList(@IdRes int id, ArrayList<RemoteViews> list,
                 int viewTypeCount) {
-            this.viewId = id;
-            this.list = list;
-            this.viewTypeCount = viewTypeCount;
+            this.mViewId = id;
+            this.mList = list;
+            this.mViewTypeCount = viewTypeCount;
         }
 
         public SetRemoteViewsAdapterList(Parcel parcel) {
-            viewId = parcel.readInt();
-            viewTypeCount = parcel.readInt();
-            list = parcel.createTypedArrayList(RemoteViews.CREATOR);
+            mViewId = parcel.readInt();
+            mViewTypeCount = parcel.readInt();
+            mList = parcel.createTypedArrayList(RemoteViews.CREATOR);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            dest.writeInt(viewTypeCount);
-            dest.writeTypedList(list, flags);
+            dest.writeInt(mViewId);
+            dest.writeInt(mViewTypeCount);
+            dest.writeTypedList(mList, flags);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             // Ensure that we are applying to an AppWidget root
             if (!(rootParent instanceof AppWidgetHostView)) {
                 Log.e(LOG_TAG, "SetRemoteViewsAdapterIntent action can only be used for " +
-                        "AppWidgets (root id: " + viewId + ")");
+                        "AppWidgets (root id: " + mViewId + ")");
                 return;
             }
             // Ensure that we are calling setRemoteAdapter on an AdapterView that supports it
             if (!(target instanceof AbsListView) && !(target instanceof AdapterViewAnimator)) {
                 Log.e(LOG_TAG, "Cannot setRemoteViewsAdapter on a view which is not " +
-                        "an AbsListView or AdapterViewAnimator (id: " + viewId + ")");
+                        "an AbsListView or AdapterViewAnimator (id: " + mViewId + ")");
                 return;
             }
 
             if (target instanceof AbsListView) {
                 AbsListView v = (AbsListView) target;
                 Adapter a = v.getAdapter();
-                if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) {
-                    ((RemoteViewsListAdapter) a).setViewsList(list);
+                if (a instanceof RemoteViewsListAdapter && mViewTypeCount <= a.getViewTypeCount()) {
+                    ((RemoteViewsListAdapter) a).setViewsList(mList);
                 } else {
-                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount,
+                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), mList, mViewTypeCount,
                             params.colorResources));
                 }
             } else if (target instanceof AdapterViewAnimator) {
                 AdapterViewAnimator v = (AdapterViewAnimator) target;
                 Adapter a = v.getAdapter();
-                if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) {
-                    ((RemoteViewsListAdapter) a).setViewsList(list);
+                if (a instanceof RemoteViewsListAdapter && mViewTypeCount <= a.getViewTypeCount()) {
+                    ((RemoteViewsListAdapter) a).setViewsList(mList);
                 } else {
-                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount,
+                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), mList, mViewTypeCount,
                             params.colorResources));
                 }
             }
@@ -1086,11 +1086,8 @@
 
         @Override
         public String getUniqueKey() {
-            return (SET_REMOTE_ADAPTER_TAG + "_" + viewId);
+            return (SET_REMOTE_ADAPTER_TAG + "_" + mViewId);
         }
-
-        int viewTypeCount;
-        ArrayList<RemoteViews> list;
     }
 
     /**
@@ -1135,19 +1132,20 @@
     }
 
     private class SetRemoteCollectionItemListAdapterAction extends Action {
-        private @NonNull CompletableFuture<RemoteCollectionItems> mItemsFuture;
+        @NonNull
+        private CompletableFuture<RemoteCollectionItems> mItemsFuture;
         final Intent mServiceIntent;
 
         SetRemoteCollectionItemListAdapterAction(@IdRes int id,
                 @NonNull RemoteCollectionItems items) {
-            viewId = id;
+            mViewId = id;
             items.setHierarchyRootData(getHierarchyRootData());
             mItemsFuture = CompletableFuture.completedFuture(items);
             mServiceIntent = null;
         }
 
         SetRemoteCollectionItemListAdapterAction(@IdRes int id, Intent intent) {
-            viewId = id;
+            mViewId = id;
             mItemsFuture = getItemsFutureFromIntentWithTimeout(intent);
             setHierarchyRootData(getHierarchyRootData());
             mServiceIntent = intent;
@@ -1196,7 +1194,7 @@
         }
 
         SetRemoteCollectionItemListAdapterAction(Parcel parcel) {
-            viewId = parcel.readInt();
+            mViewId = parcel.readInt();
             mItemsFuture = CompletableFuture.completedFuture(
                     new RemoteCollectionItems(parcel, getHierarchyRootData()));
             mServiceIntent = parcel.readTypedObject(Intent.CREATOR);
@@ -1226,7 +1224,7 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture);
             items.writeToParcel(dest, flags, /* attached= */ true);
             dest.writeTypedObject(mServiceIntent, flags);
@@ -1235,7 +1233,7 @@
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params)
                 throws ActionException {
-            View target = root.findViewById(viewId);
+            View target = root.findViewById(mViewId);
             if (target == null) return;
 
             RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture);
@@ -1243,13 +1241,13 @@
             // Ensure that we are applying to an AppWidget root
             if (!(rootParent instanceof AppWidgetHostView)) {
                 Log.e(LOG_TAG, "setRemoteAdapter can only be used for "
-                        + "AppWidgets (root id: " + viewId + ")");
+                        + "AppWidgets (root id: " + mViewId + ")");
                 return;
             }
 
             if (!(target instanceof AdapterView)) {
                 Log.e(LOG_TAG, "Cannot call setRemoteAdapter on a view which is not "
-                        + "an AdapterView (id: " + viewId + ")");
+                        + "an AdapterView (id: " + mViewId + ")");
                 return;
             }
 
@@ -1289,59 +1287,62 @@
 
         @Override
         public String getUniqueKey() {
-            return (SET_REMOTE_ADAPTER_TAG + "_" + viewId);
+            return (SET_REMOTE_ADAPTER_TAG + "_" + mViewId);
         }
     }
 
     private class SetRemoteViewsAdapterIntent extends Action {
+        Intent mIntent;
+        boolean mIsAsync = false;
+
         public SetRemoteViewsAdapterIntent(@IdRes int id, Intent intent) {
-            this.viewId = id;
-            this.intent = intent;
+            this.mViewId = id;
+            this.mIntent = intent;
         }
 
         public SetRemoteViewsAdapterIntent(Parcel parcel) {
-            viewId = parcel.readInt();
-            intent = parcel.readTypedObject(Intent.CREATOR);
+            mViewId = parcel.readInt();
+            mIntent = parcel.readTypedObject(Intent.CREATOR);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            dest.writeTypedObject(intent, flags);
+            dest.writeInt(mViewId);
+            dest.writeTypedObject(mIntent, flags);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             // Ensure that we are applying to an AppWidget root
             if (!(rootParent instanceof AppWidgetHostView)) {
                 Log.e(LOG_TAG, "setRemoteAdapter can only be used for "
-                        + "AppWidgets (root id: " + viewId + ")");
+                        + "AppWidgets (root id: " + mViewId + ")");
                 return;
             }
 
             // Ensure that we are calling setRemoteAdapter on an AdapterView that supports it
             if (!(target instanceof AbsListView) && !(target instanceof AdapterViewAnimator)) {
                 Log.e(LOG_TAG, "Cannot setRemoteAdapter on a view which is not "
-                        + "an AbsListView or AdapterViewAnimator (id: " + viewId + ")");
+                        + "an AbsListView or AdapterViewAnimator (id: " + mViewId + ")");
                 return;
             }
 
             // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
             // RemoteViewsService
             AppWidgetHostView host = (AppWidgetHostView) rootParent;
-            intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, host.getAppWidgetId())
+            mIntent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, host.getAppWidgetId())
                     .putExtra(EXTRA_REMOTEADAPTER_ON_LIGHT_BACKGROUND,
                             hasFlags(FLAG_USE_LIGHT_BACKGROUND_LAYOUT));
 
             if (target instanceof AbsListView) {
                 AbsListView v = (AbsListView) target;
-                v.setRemoteViewsAdapter(intent, isAsync);
+                v.setRemoteViewsAdapter(mIntent, mIsAsync);
                 v.setRemoteViewsInteractionHandler(params.handler);
             } else if (target instanceof AdapterViewAnimator) {
                 AdapterViewAnimator v = (AdapterViewAnimator) target;
-                v.setRemoteViewsAdapter(intent, isAsync);
+                v.setRemoteViewsAdapter(mIntent, mIsAsync);
                 v.setRemoteViewsOnClickHandler(params.handler);
             }
         }
@@ -1349,8 +1350,8 @@
         @Override
         public Action initActionAsync(ViewTree root, ViewGroup rootParent,
                 ActionApplyParams params) {
-            SetRemoteViewsAdapterIntent copy = new SetRemoteViewsAdapterIntent(viewId, intent);
-            copy.isAsync = true;
+            SetRemoteViewsAdapterIntent copy = new SetRemoteViewsAdapterIntent(mViewId, mIntent);
+            copy.mIsAsync = true;
             return copy;
         }
 
@@ -1358,9 +1359,6 @@
         public int getActionTag() {
             return SET_REMOTE_VIEW_ADAPTER_INTENT_TAG;
         }
-
-        Intent intent;
-        boolean isAsync = false;
     }
 
     /**
@@ -1369,26 +1367,27 @@
      * to launch the provided {@link PendingIntent}.
      */
     private class SetOnClickResponse extends Action {
+        final RemoteResponse mResponse;
 
         SetOnClickResponse(@IdRes int id, RemoteResponse response) {
-            this.viewId = id;
+            this.mViewId = id;
             this.mResponse = response;
         }
 
         SetOnClickResponse(Parcel parcel) {
-            viewId = parcel.readInt();
+            mViewId = parcel.readInt();
             mResponse = new RemoteResponse();
             mResponse.readFromParcel(parcel);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             mResponse.writeToParcel(dest, flags);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             if (mResponse.mPendingIntent != null) {
@@ -1397,7 +1396,7 @@
                 // AdapterView's children?
                 if (hasFlags(FLAG_WIDGET_IS_COLLECTION_CHILD)) {
                     Log.w(LOG_TAG, "Cannot SetOnClickResponse for collection item "
-                            + "(id: " + viewId + ")");
+                            + "(id: " + mViewId + ")");
                     ApplicationInfo appInfo = root.getContext().getApplicationInfo();
 
                     // We let this slide for HC and ICS so as to not break compatibility. It should
@@ -1435,8 +1434,6 @@
         public int getActionTag() {
             return SET_ON_CLICK_RESPONSE_TAG;
         }
-
-        final RemoteResponse mResponse;
     }
 
     /**
@@ -1446,32 +1443,31 @@
      * to launch the provided {@link PendingIntent}.
      */
     private class SetOnCheckedChangeResponse extends Action {
-
         private final RemoteResponse mResponse;
 
         SetOnCheckedChangeResponse(@IdRes int id, RemoteResponse response) {
-            this.viewId = id;
+            this.mViewId = id;
             this.mResponse = response;
         }
 
         SetOnCheckedChangeResponse(Parcel parcel) {
-            viewId = parcel.readInt();
+            mViewId = parcel.readInt();
             mResponse = new RemoteResponse();
             mResponse.readFromParcel(parcel);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             mResponse.writeToParcel(dest, flags);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
             if (!(target instanceof CompoundButton)) {
                 Log.w(LOG_TAG, "setOnCheckedChange methods cannot be used on "
-                        + "non-CompoundButton child (id: " + viewId + ")");
+                        + "non-CompoundButton child (id: " + mViewId + ")");
                 return;
             }
             CompoundButton button = (CompoundButton) target;
@@ -1481,7 +1477,7 @@
                 // must use setOnCheckedChangeFillInIntent instead.
                 if (hasFlags(FLAG_WIDGET_IS_COLLECTION_CHILD)) {
                     Log.w(LOG_TAG, "Cannot setOnCheckedChangePendingIntent for collection item "
-                            + "(id: " + viewId + ")");
+                            + "(id: " + mViewId + ")");
                     return;
                 }
                 target.setTagInternal(R.id.pending_intent_tag, mResponse.mPendingIntent);
@@ -1648,36 +1644,40 @@
      * <p>
      */
     private static class SetDrawableTint extends Action {
+        boolean mTargetBackground;
+        @ColorInt int mColorFilter;
+        PorterDuff.Mode mFilterMode;
+
         SetDrawableTint(@IdRes int id, boolean targetBackground,
                 @ColorInt int colorFilter, @NonNull PorterDuff.Mode mode) {
-            this.viewId = id;
-            this.targetBackground = targetBackground;
-            this.colorFilter = colorFilter;
-            this.filterMode = mode;
+            this.mViewId = id;
+            this.mTargetBackground = targetBackground;
+            this.mColorFilter = colorFilter;
+            this.mFilterMode = mode;
         }
 
         SetDrawableTint(Parcel parcel) {
-            viewId = parcel.readInt();
-            targetBackground = parcel.readInt() != 0;
-            colorFilter = parcel.readInt();
-            filterMode = PorterDuff.intToMode(parcel.readInt());
+            mViewId = parcel.readInt();
+            mTargetBackground = parcel.readInt() != 0;
+            mColorFilter = parcel.readInt();
+            mFilterMode = PorterDuff.intToMode(parcel.readInt());
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            dest.writeInt(targetBackground ? 1 : 0);
-            dest.writeInt(colorFilter);
-            dest.writeInt(PorterDuff.modeToInt(filterMode));
+            dest.writeInt(mViewId);
+            dest.writeInt(mTargetBackground ? 1 : 0);
+            dest.writeInt(mColorFilter);
+            dest.writeInt(PorterDuff.modeToInt(mFilterMode));
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             // Pick the correct drawable to modify for this view
             Drawable targetDrawable = null;
-            if (targetBackground) {
+            if (mTargetBackground) {
                 targetDrawable = target.getBackground();
             } else if (target instanceof ImageView) {
                 ImageView imageView = (ImageView) target;
@@ -1685,7 +1685,7 @@
             }
 
             if (targetDrawable != null) {
-                targetDrawable.mutate().setColorFilter(colorFilter, filterMode);
+                targetDrawable.mutate().setColorFilter(mColorFilter, mFilterMode);
             }
         }
 
@@ -1693,10 +1693,6 @@
         public int getActionTag() {
             return SET_DRAWABLE_TINT_TAG;
         }
-
-        boolean targetBackground;
-        @ColorInt int colorFilter;
-        PorterDuff.Mode filterMode;
     }
 
     /**
@@ -1709,27 +1705,26 @@
      * <p>
      */
     private class SetRippleDrawableColor extends Action {
-
         ColorStateList mColorStateList;
 
         SetRippleDrawableColor(@IdRes int id, ColorStateList colorStateList) {
-            this.viewId = id;
+            this.mViewId = id;
             this.mColorStateList = colorStateList;
         }
 
         SetRippleDrawableColor(Parcel parcel) {
-            viewId = parcel.readInt();
+            mViewId = parcel.readInt();
             mColorStateList = parcel.readParcelable(null, android.content.res.ColorStateList.class);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             dest.writeParcelable(mColorStateList, 0);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             // Pick the correct drawable to modify for this view
@@ -1756,23 +1751,23 @@
         final boolean mNext;
 
         ViewContentNavigation(@IdRes int viewId, boolean next) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             this.mNext = next;
         }
 
         ViewContentNavigation(Parcel in) {
-            this.viewId = in.readInt();
+            this.mViewId = in.readInt();
             this.mNext = in.readBoolean();
         }
 
         public void writeToParcel(Parcel out, int flags) {
-            out.writeInt(this.viewId);
+            out.writeInt(this.mViewId);
             out.writeBoolean(this.mNext);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View view = root.findViewById(viewId);
+            final View view = root.findViewById(mViewId);
             if (view == null) return;
 
             try {
@@ -1794,7 +1789,6 @@
     }
 
     private static class BitmapCache {
-
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         ArrayList<Bitmap> mBitmaps;
         SparseIntArray mBitmapHashes;
@@ -1861,45 +1855,45 @@
     }
 
     private class BitmapReflectionAction extends Action {
-        int bitmapId;
+        int mBitmapId;
         @UnsupportedAppUsage
-        Bitmap bitmap;
+        Bitmap mBitmap;
         @UnsupportedAppUsage
-        String methodName;
+        String mMethodName;
 
         BitmapReflectionAction(@IdRes int viewId, String methodName, Bitmap bitmap) {
-            this.bitmap = bitmap;
-            this.viewId = viewId;
-            this.methodName = methodName;
-            bitmapId = mBitmapCache.getBitmapId(bitmap);
+            this.mBitmap = bitmap;
+            this.mViewId = viewId;
+            this.mMethodName = methodName;
+            mBitmapId = mBitmapCache.getBitmapId(bitmap);
         }
 
         BitmapReflectionAction(Parcel in) {
-            viewId = in.readInt();
-            methodName = in.readString8();
-            bitmapId = in.readInt();
-            bitmap = mBitmapCache.getBitmapForId(bitmapId);
+            mViewId = in.readInt();
+            mMethodName = in.readString8();
+            mBitmapId = in.readInt();
+            mBitmap = mBitmapCache.getBitmapForId(mBitmapId);
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            dest.writeString8(methodName);
-            dest.writeInt(bitmapId);
+            dest.writeInt(mViewId);
+            dest.writeString8(mMethodName);
+            dest.writeInt(mBitmapId);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params)
                 throws ActionException {
-            ReflectionAction ra = new ReflectionAction(viewId, methodName,
+            ReflectionAction ra = new ReflectionAction(mViewId, mMethodName,
                     BaseReflectionAction.BITMAP,
-                    bitmap);
+                    mBitmap);
             ra.apply(root, rootParent, params);
         }
 
         @Override
         public void setHierarchyRootData(HierarchyRootData rootData) {
-            bitmapId = rootData.mBitmapCache.getBitmapId(bitmap);
+            mBitmapId = rootData.mBitmapCache.getBitmapId(mBitmap);
         }
 
         @Override
@@ -1933,30 +1927,30 @@
         static final int BLEND_MODE = 17;
 
         @UnsupportedAppUsage
-        String methodName;
-        int type;
+        String mMethodName;
+        int mType;
 
         BaseReflectionAction(@IdRes int viewId, String methodName, int type) {
-            this.viewId = viewId;
-            this.methodName = methodName;
-            this.type = type;
+            this.mViewId = viewId;
+            this.mMethodName = methodName;
+            this.mType = type;
         }
 
         BaseReflectionAction(Parcel in) {
-            this.viewId = in.readInt();
-            this.methodName = in.readString8();
-            this.type = in.readInt();
+            this.mViewId = in.readInt();
+            this.mMethodName = in.readString8();
+            this.mType = in.readInt();
             //noinspection ConstantIfStatement
             if (false) {
-                Log.d(LOG_TAG, "read viewId=0x" + Integer.toHexString(this.viewId)
-                        + " methodName=" + this.methodName + " type=" + this.type);
+                Log.d(LOG_TAG, "read viewId=0x" + Integer.toHexString(this.mViewId)
+                        + " methodName=" + this.mMethodName + " type=" + this.mType);
             }
         }
 
         public void writeToParcel(Parcel out, int flags) {
-            out.writeInt(this.viewId);
-            out.writeString8(this.methodName);
-            out.writeInt(this.type);
+            out.writeInt(this.mViewId);
+            out.writeString8(this.mMethodName);
+            out.writeInt(this.mType);
         }
 
         /**
@@ -1971,16 +1965,16 @@
 
         @Override
         public final void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View view = root.findViewById(viewId);
+            final View view = root.findViewById(mViewId);
             if (view == null) return;
 
-            Class<?> param = getParameterType(this.type);
+            Class<?> param = getParameterType(this.mType);
             if (param == null) {
-                throw new ActionException("bad type: " + this.type);
+                throw new ActionException("bad type: " + this.mType);
             }
             Object value = getParameterValue(view);
             try {
-                getMethod(view, this.methodName, param, false /* async */).invoke(view, value);
+                getMethod(view, this.mMethodName, param, false /* async */).invoke(view, value);
             } catch (Throwable ex) {
                 throw new ActionException(ex);
             }
@@ -1989,17 +1983,17 @@
         @Override
         public final Action initActionAsync(ViewTree root, ViewGroup rootParent,
                 ActionApplyParams params) {
-            final View view = root.findViewById(viewId);
+            final View view = root.findViewById(mViewId);
             if (view == null) return ACTION_NOOP;
 
-            Class<?> param = getParameterType(this.type);
+            Class<?> param = getParameterType(this.mType);
             if (param == null) {
-                throw new ActionException("bad type: " + this.type);
+                throw new ActionException("bad type: " + this.mType);
             }
 
             Object value = getParameterValue(view);
             try {
-                MethodHandle method = getMethod(view, this.methodName, param, true /* async */);
+                MethodHandle method = getMethod(view, this.mMethodName, param, true /* async */);
                 // Upload the bitmap to GPU if the parameter is of type Bitmap or Icon.
                 // Since bitmaps in framework are seldomly modified, this is supposed to accelerate
                 // the operations.
@@ -2025,7 +2019,7 @@
                     if (endAction instanceof ViewStub.ViewReplaceRunnable) {
                         root.createTree();
                         // Replace child tree
-                        root.findViewTreeById(viewId).replaceView(
+                        root.findViewTreeById(mViewId).replaceView(
                                 ((ViewStub.ViewReplaceRunnable) endAction).view);
                     }
                     return new RunnableAction(endAction);
@@ -2039,7 +2033,7 @@
 
         public final int mergeBehavior() {
             // smoothScrollBy is cumulative, everything else overwites.
-            if (methodName.equals("smoothScrollBy")) {
+            if (mMethodName.equals("smoothScrollBy")) {
                 return MERGE_APPEND;
             } else {
                 return MERGE_REPLACE;
@@ -2050,17 +2044,17 @@
         public final String getUniqueKey() {
             // Each type of reflection action corresponds to a setter, so each should be seen as
             // unique from the standpoint of merging.
-            return super.getUniqueKey() + this.methodName + this.type;
+            return super.getUniqueKey() + this.mMethodName + this.mType;
         }
 
         @Override
         public final boolean prefersAsyncApply() {
-            return this.type == URI || this.type == ICON;
+            return this.mType == URI || this.mType == ICON;
         }
 
         @Override
         public void visitUris(@NonNull Consumer<Uri> visitor) {
-            switch (this.type) {
+            switch (this.mType) {
                 case URI:
                     final Uri uri = (Uri) getParameterValue(null);
                     if (uri != null) visitor.accept(uri);
@@ -2076,53 +2070,53 @@
     /** Class for the reflection actions. */
     private static final class ReflectionAction extends BaseReflectionAction {
         @UnsupportedAppUsage
-        Object value;
+        Object mValue;
 
         ReflectionAction(@IdRes int viewId, String methodName, int type, Object value) {
             super(viewId, methodName, type);
-            this.value = value;
+            this.mValue = value;
         }
 
         ReflectionAction(Parcel in) {
             super(in);
             // For some values that may have been null, we first check a flag to see if they were
             // written to the parcel.
-            switch (this.type) {
+            switch (this.mType) {
                 case BOOLEAN:
-                    this.value = in.readBoolean();
+                    this.mValue = in.readBoolean();
                     break;
                 case BYTE:
-                    this.value = in.readByte();
+                    this.mValue = in.readByte();
                     break;
                 case SHORT:
-                    this.value = (short) in.readInt();
+                    this.mValue = (short) in.readInt();
                     break;
                 case INT:
-                    this.value = in.readInt();
+                    this.mValue = in.readInt();
                     break;
                 case LONG:
-                    this.value = in.readLong();
+                    this.mValue = in.readLong();
                     break;
                 case FLOAT:
-                    this.value = in.readFloat();
+                    this.mValue = in.readFloat();
                     break;
                 case DOUBLE:
-                    this.value = in.readDouble();
+                    this.mValue = in.readDouble();
                     break;
                 case CHAR:
-                    this.value = (char) in.readInt();
+                    this.mValue = (char) in.readInt();
                     break;
                 case STRING:
-                    this.value = in.readString8();
+                    this.mValue = in.readString8();
                     break;
                 case CHAR_SEQUENCE:
-                    this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+                    this.mValue = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
                     break;
                 case URI:
-                    this.value = in.readTypedObject(Uri.CREATOR);
+                    this.mValue = in.readTypedObject(Uri.CREATOR);
                     break;
                 case BITMAP:
-                    this.value = in.readTypedObject(Bitmap.CREATOR);
+                    this.mValue = in.readTypedObject(Bitmap.CREATOR);
                     break;
                 case BUNDLE:
                     // Because we use Parcel.allowSquashing() when writing, and that affects
@@ -2131,24 +2125,24 @@
                     //  just happens to have that effect on Bundle.readFromParcel().
                     // TODO(b/212731590): build this state tracking into Bundle
                     if (in.hasReadWriteHelper()) {
-                        this.value = in.readBundle();
+                        this.mValue = in.readBundle();
                     } else {
                         in.setReadWriteHelper(ALTERNATIVE_DEFAULT);
-                        this.value = in.readBundle();
+                        this.mValue = in.readBundle();
                         in.setReadWriteHelper(null);
                     }
                     break;
                 case INTENT:
-                    this.value = in.readTypedObject(Intent.CREATOR);
+                    this.mValue = in.readTypedObject(Intent.CREATOR);
                     break;
                 case COLOR_STATE_LIST:
-                    this.value = in.readTypedObject(ColorStateList.CREATOR);
+                    this.mValue = in.readTypedObject(ColorStateList.CREATOR);
                     break;
                 case ICON:
-                    this.value = in.readTypedObject(Icon.CREATOR);
+                    this.mValue = in.readTypedObject(Icon.CREATOR);
                     break;
                 case BLEND_MODE:
-                    this.value = BlendMode.fromValue(in.readInt());
+                    this.mValue = BlendMode.fromValue(in.readInt());
                     break;
                 default:
                     break;
@@ -2159,49 +2153,49 @@
             super.writeToParcel(out, flags);
             // For some values which are null, we record an integer flag to indicate whether
             // we have written a valid value to the parcel.
-            switch (this.type) {
+            switch (this.mType) {
                 case BOOLEAN:
-                    out.writeBoolean((Boolean) this.value);
+                    out.writeBoolean((Boolean) this.mValue);
                     break;
                 case BYTE:
-                    out.writeByte((Byte) this.value);
+                    out.writeByte((Byte) this.mValue);
                     break;
                 case SHORT:
-                    out.writeInt((Short) this.value);
+                    out.writeInt((Short) this.mValue);
                     break;
                 case INT:
-                    out.writeInt((Integer) this.value);
+                    out.writeInt((Integer) this.mValue);
                     break;
                 case LONG:
-                    out.writeLong((Long) this.value);
+                    out.writeLong((Long) this.mValue);
                     break;
                 case FLOAT:
-                    out.writeFloat((Float) this.value);
+                    out.writeFloat((Float) this.mValue);
                     break;
                 case DOUBLE:
-                    out.writeDouble((Double) this.value);
+                    out.writeDouble((Double) this.mValue);
                     break;
                 case CHAR:
-                    out.writeInt((int) ((Character) this.value).charValue());
+                    out.writeInt((int) ((Character) this.mValue).charValue());
                     break;
                 case STRING:
-                    out.writeString8((String) this.value);
+                    out.writeString8((String) this.mValue);
                     break;
                 case CHAR_SEQUENCE:
-                    TextUtils.writeToParcel((CharSequence) this.value, out, flags);
+                    TextUtils.writeToParcel((CharSequence) this.mValue, out, flags);
                     break;
                 case BUNDLE:
-                    out.writeBundle((Bundle) this.value);
+                    out.writeBundle((Bundle) this.mValue);
                     break;
                 case BLEND_MODE:
-                    out.writeInt(BlendMode.toValue((BlendMode) this.value));
+                    out.writeInt(BlendMode.toValue((BlendMode) this.mValue));
                     break;
                 case URI:
                 case BITMAP:
                 case INTENT:
                 case COLOR_STATE_LIST:
                 case ICON:
-                    out.writeTypedObject((Parcelable) this.value, flags);
+                    out.writeTypedObject((Parcelable) this.mValue, flags);
                     break;
                 default:
                     break;
@@ -2211,7 +2205,7 @@
         @Nullable
         @Override
         protected Object getParameterValue(@Nullable View view) throws ActionException {
-            return this.value;
+            return this.mValue;
         }
 
         @Override
@@ -2221,7 +2215,6 @@
     }
 
     private static final class ResourceReflectionAction extends BaseReflectionAction {
-
         static final int DIMEN_RESOURCE = 1;
         static final int COLOR_RESOURCE = 2;
         static final int STRING_RESOURCE = 3;
@@ -2258,7 +2251,7 @@
             try {
                 switch (this.mResourceType) {
                     case DIMEN_RESOURCE:
-                        switch (this.type) {
+                        switch (this.mType) {
                             case BaseReflectionAction.INT:
                                 return mResId == 0 ? 0 : resources.getDimensionPixelSize(mResId);
                             case BaseReflectionAction.FLOAT:
@@ -2266,10 +2259,10 @@
                             default:
                                 throw new ActionException(
                                         "dimen resources must be used as INT or FLOAT, "
-                                                + "not " + this.type);
+                                                + "not " + this.mType);
                         }
                     case COLOR_RESOURCE:
-                        switch (this.type) {
+                        switch (this.mType) {
                             case BaseReflectionAction.INT:
                                 return mResId == 0 ? 0 : view.getContext().getColor(mResId);
                             case BaseReflectionAction.COLOR_STATE_LIST:
@@ -2278,10 +2271,10 @@
                             default:
                                 throw new ActionException(
                                         "color resources must be used as INT or COLOR_STATE_LIST,"
-                                                + " not " + this.type);
+                                                + " not " + this.mType);
                         }
                     case STRING_RESOURCE:
-                        switch (this.type) {
+                        switch (this.mType) {
                             case BaseReflectionAction.CHAR_SEQUENCE:
                                 return mResId == 0 ? null : resources.getText(mResId);
                             case BaseReflectionAction.STRING:
@@ -2289,7 +2282,7 @@
                             default:
                                 throw new ActionException(
                                         "string resources must be used as STRING or CHAR_SEQUENCE,"
-                                                + " not " + this.type);
+                                                + " not " + this.mType);
                         }
                     default:
                         throw new ActionException("unknown resource type: " + this.mResourceType);
@@ -2308,7 +2301,6 @@
     }
 
     private static final class AttributeReflectionAction extends BaseReflectionAction {
-
         static final int DIMEN_RESOURCE = 1;
         static final int COLOR_RESOURCE = 2;
         static final int STRING_RESOURCE = 3;
@@ -2347,7 +2339,7 @@
                 }
                 switch (this.mResourceType) {
                     case DIMEN_RESOURCE:
-                        switch (this.type) {
+                        switch (this.mType) {
                             case BaseReflectionAction.INT:
                                 return typedArray.getDimensionPixelSize(0, 0);
                             case BaseReflectionAction.FLOAT:
@@ -2356,10 +2348,10 @@
                                 throw new ActionException(
                                         "dimen attribute 0x" + Integer.toHexString(this.mAttrId)
                                                 + " must be used as INT or FLOAT,"
-                                                + " not " + this.type);
+                                                + " not " + this.mType);
                         }
                     case COLOR_RESOURCE:
-                        switch (this.type) {
+                        switch (this.mType) {
                             case BaseReflectionAction.INT:
                                 return typedArray.getColor(0, 0);
                             case BaseReflectionAction.COLOR_STATE_LIST:
@@ -2368,10 +2360,10 @@
                                 throw new ActionException(
                                         "color attribute 0x" + Integer.toHexString(this.mAttrId)
                                                 + " must be used as INT or COLOR_STATE_LIST,"
-                                                + " not " + this.type);
+                                                + " not " + this.mType);
                         }
                     case STRING_RESOURCE:
-                        switch (this.type) {
+                        switch (this.mType) {
                             case BaseReflectionAction.CHAR_SEQUENCE:
                                 return typedArray.getText(0);
                             case BaseReflectionAction.STRING:
@@ -2380,7 +2372,7 @@
                                 throw new ActionException(
                                         "string attribute 0x" + Integer.toHexString(this.mAttrId)
                                                 + " must be used as STRING or CHAR_SEQUENCE,"
-                                                + " not " + this.type);
+                                                + " not " + this.mType);
                         }
                     default:
                         // Note: This can only be an implementation error.
@@ -2402,7 +2394,6 @@
         }
     }
     private static final class ComplexUnitDimensionReflectionAction extends BaseReflectionAction {
-
         private final float mValue;
         @ComplexDimensionUnit
         private final int mUnit;
@@ -2435,14 +2426,14 @@
             DisplayMetrics dm = view.getContext().getResources().getDisplayMetrics();
             try {
                 int data = TypedValue.createComplexDimension(this.mValue, this.mUnit);
-                switch (this.type) {
+                switch (this.mType) {
                     case ReflectionAction.INT:
                         return TypedValue.complexToDimensionPixelSize(data, dm);
                     case ReflectionAction.FLOAT:
                         return TypedValue.complexToDimension(data, dm);
                     default:
                         throw new ActionException(
-                                "parameter type must be INT or FLOAT, not " + this.type);
+                                "parameter type must be INT or FLOAT, not " + this.mType);
                 }
             } catch (ActionException ex) {
                 throw ex;
@@ -2458,7 +2449,6 @@
     }
 
     private static final class NightModeReflectionAction extends BaseReflectionAction {
-
         private final Object mLightValue;
         private final Object mDarkValue;
 
@@ -2475,7 +2465,7 @@
 
         NightModeReflectionAction(Parcel in) {
             super(in);
-            switch (this.type) {
+            switch (this.mType) {
                 case ICON:
                     mLightValue = in.readTypedObject(Icon.CREATOR);
                     mDarkValue = in.readTypedObject(Icon.CREATOR);
@@ -2489,14 +2479,14 @@
                     mDarkValue = in.readInt();
                     break;
                 default:
-                    throw new ActionException("Unexpected night mode action type: " + this.type);
+                    throw new ActionException("Unexpected night mode action type: " + this.mType);
             }
         }
 
         @Override
         public void writeToParcel(Parcel out, int flags) {
             super.writeToParcel(out, flags);
-            switch (this.type) {
+            switch (this.mType) {
                 case ICON:
                 case COLOR_STATE_LIST:
                     out.writeTypedObject((Parcelable) mLightValue, flags);
@@ -2525,7 +2515,7 @@
 
         @Override
         public void visitUris(@NonNull Consumer<Uri> visitor) {
-            if (this.type == ICON) {
+            if (this.mType == ICON) {
                 visitIconUri((Icon) mDarkValue, visitor);
                 visitIconUri((Icon) mLightValue, visitor);
             }
@@ -2617,7 +2607,7 @@
         }
 
         ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews, int index, int stableId) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             mNestedViews = nestedViews;
             mIndex = index;
             mStableId = stableId;
@@ -2625,7 +2615,7 @@
         }
 
         ViewGroupActionAdd(Parcel parcel, ApplicationInfo info, int depth) {
-            viewId = parcel.readInt();
+            mViewId = parcel.readInt();
             mIndex = parcel.readInt();
             mStableId = parcel.readInt();
             mNestedViews = new RemoteViews(parcel, getHierarchyRootData(), info, depth);
@@ -2633,7 +2623,7 @@
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             dest.writeInt(mIndex);
             dest.writeInt(mStableId);
             mNestedViews.writeToParcel(dest, flags);
@@ -2658,7 +2648,7 @@
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
             final Context context = root.getContext();
-            final ViewGroup target = root.findViewById(viewId);
+            final ViewGroup target = root.findViewById(mViewId);
 
             if (target == null) {
                 return;
@@ -2713,7 +2703,7 @@
             // In the async implementation, update the view tree so that subsequent calls to
             // findViewById return the current view.
             root.createTree();
-            ViewTree target = root.findViewTreeById(viewId);
+            ViewTree target = root.findViewTreeById(mViewId);
             if ((target == null) || !(target.mRoot instanceof ViewGroup)) {
                 return ACTION_NOOP;
             }
@@ -2845,23 +2835,23 @@
         }
 
         ViewGroupActionRemove(@IdRes int viewId, @IdRes int viewIdToKeep) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             mViewIdToKeep = viewIdToKeep;
         }
 
         ViewGroupActionRemove(Parcel parcel) {
-            viewId = parcel.readInt();
+            mViewId = parcel.readInt();
             mViewIdToKeep = parcel.readInt();
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             dest.writeInt(mViewIdToKeep);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final ViewGroup target = root.findViewById(viewId);
+            final ViewGroup target = root.findViewById(mViewId);
 
             if (target == null) {
                 return;
@@ -2888,7 +2878,7 @@
             // In the async implementation, update the view tree so that subsequent calls to
             // findViewById return the current view.
             root.createTree();
-            ViewTree target = root.findViewTreeById(viewId);
+            ViewTree target = root.findViewTreeById(mViewId);
 
             if ((target == null) || !(target.mRoot instanceof ViewGroup)) {
                 return ACTION_NOOP;
@@ -2953,22 +2943,21 @@
      * Action to remove a view from its parent.
      */
     private static class RemoveFromParentAction extends Action {
-
         RemoveFromParentAction(@IdRes int viewId) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
         }
 
         RemoveFromParentAction(Parcel parcel) {
-            viewId = parcel.readInt();
+            mViewId = parcel.readInt();
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
 
             if (target == null || target == root) {
                 return;
@@ -2986,7 +2975,7 @@
             // In the async implementation, update the view tree so that subsequent calls to
             // findViewById return the correct view.
             root.createTree();
-            ViewTree target = root.findViewTreeById(viewId);
+            ViewTree target = root.findViewTreeById(mViewId);
 
             if (target == null || target == root) {
                 return ACTION_NOOP;
@@ -3023,88 +3012,96 @@
      * (s/t/e/b) or cardinal (l/t/r/b) arrangement.
      */
     private static class TextViewDrawableAction extends Action {
+        boolean mIsRelative = false;
+        boolean mUseIcons = false;
+        int mD1, mD2, mD3, mD4;
+        Icon mI1, mI2, mI3, mI4;
+
+        boolean mDrawablesLoaded = false;
+        Drawable mId1, mId2, mId3, mId4;
+
         public TextViewDrawableAction(@IdRes int viewId, boolean isRelative, @DrawableRes int d1,
                 @DrawableRes int d2, @DrawableRes int d3, @DrawableRes int d4) {
-            this.viewId = viewId;
-            this.isRelative = isRelative;
-            this.useIcons = false;
-            this.d1 = d1;
-            this.d2 = d2;
-            this.d3 = d3;
-            this.d4 = d4;
+            this.mViewId = viewId;
+            this.mIsRelative = isRelative;
+            this.mUseIcons = false;
+            this.mD1 = d1;
+            this.mD2 = d2;
+            this.mD3 = d3;
+            this.mD4 = d4;
         }
 
         public TextViewDrawableAction(@IdRes int viewId, boolean isRelative,
                 Icon i1, Icon i2, Icon i3, Icon i4) {
-            this.viewId = viewId;
-            this.isRelative = isRelative;
-            this.useIcons = true;
-            this.i1 = i1;
-            this.i2 = i2;
-            this.i3 = i3;
-            this.i4 = i4;
+            this.mViewId = viewId;
+            this.mIsRelative = isRelative;
+            this.mUseIcons = true;
+            this.mI1 = i1;
+            this.mI2 = i2;
+            this.mI3 = i3;
+            this.mI4 = i4;
         }
 
         public TextViewDrawableAction(Parcel parcel) {
-            viewId = parcel.readInt();
-            isRelative = (parcel.readInt() != 0);
-            useIcons = (parcel.readInt() != 0);
-            if (useIcons) {
-                i1 = parcel.readTypedObject(Icon.CREATOR);
-                i2 = parcel.readTypedObject(Icon.CREATOR);
-                i3 = parcel.readTypedObject(Icon.CREATOR);
-                i4 = parcel.readTypedObject(Icon.CREATOR);
+            mViewId = parcel.readInt();
+            mIsRelative = (parcel.readInt() != 0);
+            mUseIcons = (parcel.readInt() != 0);
+            if (mUseIcons) {
+                mI1 = parcel.readTypedObject(Icon.CREATOR);
+                mI2 = parcel.readTypedObject(Icon.CREATOR);
+                mI3 = parcel.readTypedObject(Icon.CREATOR);
+                mI4 = parcel.readTypedObject(Icon.CREATOR);
             } else {
-                d1 = parcel.readInt();
-                d2 = parcel.readInt();
-                d3 = parcel.readInt();
-                d4 = parcel.readInt();
+                mD1 = parcel.readInt();
+                mD2 = parcel.readInt();
+                mD3 = parcel.readInt();
+                mD4 = parcel.readInt();
             }
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            dest.writeInt(isRelative ? 1 : 0);
-            dest.writeInt(useIcons ? 1 : 0);
-            if (useIcons) {
-                dest.writeTypedObject(i1, 0);
-                dest.writeTypedObject(i2, 0);
-                dest.writeTypedObject(i3, 0);
-                dest.writeTypedObject(i4, 0);
+            dest.writeInt(mViewId);
+            dest.writeInt(mIsRelative ? 1 : 0);
+            dest.writeInt(mUseIcons ? 1 : 0);
+            if (mUseIcons) {
+                dest.writeTypedObject(mI1, 0);
+                dest.writeTypedObject(mI2, 0);
+                dest.writeTypedObject(mI3, 0);
+                dest.writeTypedObject(mI4, 0);
             } else {
-                dest.writeInt(d1);
-                dest.writeInt(d2);
-                dest.writeInt(d3);
-                dest.writeInt(d4);
+                dest.writeInt(mD1);
+                dest.writeInt(mD2);
+                dest.writeInt(mD3);
+                dest.writeInt(mD4);
             }
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final TextView target = root.findViewById(viewId);
+            final TextView target = root.findViewById(mViewId);
             if (target == null) return;
-            if (drawablesLoaded) {
-                if (isRelative) {
-                    target.setCompoundDrawablesRelativeWithIntrinsicBounds(id1, id2, id3, id4);
+            if (mDrawablesLoaded) {
+                if (mIsRelative) {
+                    target.setCompoundDrawablesRelativeWithIntrinsicBounds(mId1, mId2, mId3, mId4);
                 } else {
-                    target.setCompoundDrawablesWithIntrinsicBounds(id1, id2, id3, id4);
+                    target.setCompoundDrawablesWithIntrinsicBounds(mId1, mId2, mId3, mId4);
                 }
-            } else if (useIcons) {
+            } else if (mUseIcons) {
                 final Context ctx = target.getContext();
-                final Drawable id1 = i1 == null ? null : i1.loadDrawable(ctx);
-                final Drawable id2 = i2 == null ? null : i2.loadDrawable(ctx);
-                final Drawable id3 = i3 == null ? null : i3.loadDrawable(ctx);
-                final Drawable id4 = i4 == null ? null : i4.loadDrawable(ctx);
-                if (isRelative) {
+                final Drawable id1 = mI1 == null ? null : mI1.loadDrawable(ctx);
+                final Drawable id2 = mI2 == null ? null : mI2.loadDrawable(ctx);
+                final Drawable id3 = mI3 == null ? null : mI3.loadDrawable(ctx);
+                final Drawable id4 = mI4 == null ? null : mI4.loadDrawable(ctx);
+                if (mIsRelative) {
                     target.setCompoundDrawablesRelativeWithIntrinsicBounds(id1, id2, id3, id4);
                 } else {
                     target.setCompoundDrawablesWithIntrinsicBounds(id1, id2, id3, id4);
                 }
             } else {
-                if (isRelative) {
-                    target.setCompoundDrawablesRelativeWithIntrinsicBounds(d1, d2, d3, d4);
+                if (mIsRelative) {
+                    target.setCompoundDrawablesRelativeWithIntrinsicBounds(mD1, mD2, mD3, mD4);
                 } else {
-                    target.setCompoundDrawablesWithIntrinsicBounds(d1, d2, d3, d4);
+                    target.setCompoundDrawablesWithIntrinsicBounds(mD1, mD2, mD3, mD4);
                 }
             }
         }
@@ -3112,34 +3109,34 @@
         @Override
         public Action initActionAsync(ViewTree root, ViewGroup rootParent,
                 ActionApplyParams params) {
-            final TextView target = root.findViewById(viewId);
+            final TextView target = root.findViewById(mViewId);
             if (target == null) return ACTION_NOOP;
 
-            TextViewDrawableAction copy = useIcons ?
-                    new TextViewDrawableAction(viewId, isRelative, i1, i2, i3, i4) :
-                    new TextViewDrawableAction(viewId, isRelative, d1, d2, d3, d4);
+            TextViewDrawableAction copy = mUseIcons
+                    ? new TextViewDrawableAction(mViewId, mIsRelative, mI1, mI2, mI3, mI4)
+                    : new TextViewDrawableAction(mViewId, mIsRelative, mD1, mD2, mD3, mD4);
 
             // Load the drawables on the background thread.
-            copy.drawablesLoaded = true;
+            copy.mDrawablesLoaded = true;
             final Context ctx = target.getContext();
 
-            if (useIcons) {
-                copy.id1 = i1 == null ? null : i1.loadDrawable(ctx);
-                copy.id2 = i2 == null ? null : i2.loadDrawable(ctx);
-                copy.id3 = i3 == null ? null : i3.loadDrawable(ctx);
-                copy.id4 = i4 == null ? null : i4.loadDrawable(ctx);
+            if (mUseIcons) {
+                copy.mId1 = mI1 == null ? null : mI1.loadDrawable(ctx);
+                copy.mId2 = mI2 == null ? null : mI2.loadDrawable(ctx);
+                copy.mId3 = mI3 == null ? null : mI3.loadDrawable(ctx);
+                copy.mId4 = mI4 == null ? null : mI4.loadDrawable(ctx);
             } else {
-                copy.id1 = d1 == 0 ? null : ctx.getDrawable(d1);
-                copy.id2 = d2 == 0 ? null : ctx.getDrawable(d2);
-                copy.id3 = d3 == 0 ? null : ctx.getDrawable(d3);
-                copy.id4 = d4 == 0 ? null : ctx.getDrawable(d4);
+                copy.mId1 = mD1 == 0 ? null : ctx.getDrawable(mD1);
+                copy.mId2 = mD2 == 0 ? null : ctx.getDrawable(mD2);
+                copy.mId3 = mD3 == 0 ? null : ctx.getDrawable(mD3);
+                copy.mId4 = mD4 == 0 ? null : ctx.getDrawable(mD4);
             }
             return copy;
         }
 
         @Override
         public boolean prefersAsyncApply() {
-            return useIcons;
+            return mUseIcons;
         }
 
         @Override
@@ -3149,110 +3146,101 @@
 
         @Override
         public void visitUris(@NonNull Consumer<Uri> visitor) {
-            if (useIcons) {
-                visitIconUri(i1, visitor);
-                visitIconUri(i2, visitor);
-                visitIconUri(i3, visitor);
-                visitIconUri(i4, visitor);
+            if (mUseIcons) {
+                visitIconUri(mI1, visitor);
+                visitIconUri(mI2, visitor);
+                visitIconUri(mI3, visitor);
+                visitIconUri(mI4, visitor);
             }
         }
-
-        boolean isRelative = false;
-        boolean useIcons = false;
-        int d1, d2, d3, d4;
-        Icon i1, i2, i3, i4;
-
-        boolean drawablesLoaded = false;
-        Drawable id1, id2, id3, id4;
     }
 
     /**
      * Helper action to set text size on a TextView in any supported units.
      */
     private static class TextViewSizeAction extends Action {
+        int mUnits;
+        float mSize;
+
         TextViewSizeAction(@IdRes int viewId, @ComplexDimensionUnit int units, float size) {
-            this.viewId = viewId;
-            this.units = units;
-            this.size = size;
+            this.mViewId = viewId;
+            this.mUnits = units;
+            this.mSize = size;
         }
 
         TextViewSizeAction(Parcel parcel) {
-            viewId = parcel.readInt();
-            units = parcel.readInt();
-            size  = parcel.readFloat();
+            mViewId = parcel.readInt();
+            mUnits = parcel.readInt();
+            mSize = parcel.readFloat();
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            dest.writeInt(units);
-            dest.writeFloat(size);
+            dest.writeInt(mViewId);
+            dest.writeInt(mUnits);
+            dest.writeFloat(mSize);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final TextView target = root.findViewById(viewId);
+            final TextView target = root.findViewById(mViewId);
             if (target == null) return;
-            target.setTextSize(units, size);
+            target.setTextSize(mUnits, mSize);
         }
 
         @Override
         public int getActionTag() {
             return TEXT_VIEW_SIZE_ACTION_TAG;
         }
-
-        int units;
-        float size;
     }
 
     /**
      * Helper action to set padding on a View.
      */
     private static class ViewPaddingAction extends Action {
+        @Px int mLeft, mTop, mRight, mBottom;
+
         public ViewPaddingAction(@IdRes int viewId, @Px int left, @Px int top,
                 @Px int right, @Px int bottom) {
-            this.viewId = viewId;
-            this.left = left;
-            this.top = top;
-            this.right = right;
-            this.bottom = bottom;
+            this.mViewId = viewId;
+            this.mLeft = left;
+            this.mTop = top;
+            this.mRight = right;
+            this.mBottom = bottom;
         }
 
         public ViewPaddingAction(Parcel parcel) {
-            viewId = parcel.readInt();
-            left = parcel.readInt();
-            top = parcel.readInt();
-            right = parcel.readInt();
-            bottom = parcel.readInt();
+            mViewId = parcel.readInt();
+            mLeft = parcel.readInt();
+            mTop = parcel.readInt();
+            mRight = parcel.readInt();
+            mBottom = parcel.readInt();
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            dest.writeInt(left);
-            dest.writeInt(top);
-            dest.writeInt(right);
-            dest.writeInt(bottom);
+            dest.writeInt(mViewId);
+            dest.writeInt(mLeft);
+            dest.writeInt(mTop);
+            dest.writeInt(mRight);
+            dest.writeInt(mBottom);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
-            target.setPadding(left, top, right, bottom);
+            target.setPadding(mLeft, mTop, mRight, mBottom);
         }
 
         @Override
         public int getActionTag() {
             return VIEW_PADDING_ACTION_TAG;
         }
-
-        @Px int left, top, right, bottom;
     }
 
     /**
      * Helper action to set layout params on a View.
      */
     private static class LayoutParamAction extends Action {
-
         static final int LAYOUT_MARGIN_LEFT = MARGIN_LEFT;
         static final int LAYOUT_MARGIN_TOP = MARGIN_TOP;
         static final int LAYOUT_MARGIN_RIGHT = MARGIN_RIGHT;
@@ -3274,7 +3262,7 @@
          */
         LayoutParamAction(@IdRes int viewId, int property, float value,
                 @ComplexDimensionUnit int units) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             this.mProperty = property;
             this.mValueType = VALUE_TYPE_COMPLEX_UNIT;
             this.mValue = TypedValue.createComplexDimension(value, units);
@@ -3289,21 +3277,21 @@
          *   {@link #VALUE_TYPE_RAW}.
          */
         LayoutParamAction(@IdRes int viewId, int property, int value, @ValueType int valueType) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             this.mProperty = property;
             this.mValueType = valueType;
             this.mValue = value;
         }
 
         public LayoutParamAction(Parcel parcel) {
-            viewId = parcel.readInt();
+            mViewId = parcel.readInt();
             mProperty = parcel.readInt();
             mValueType = parcel.readInt();
             mValue = parcel.readInt();
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             dest.writeInt(mProperty);
             dest.writeInt(mValueType);
             dest.writeInt(mValue);
@@ -3311,7 +3299,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) {
                 return;
             }
@@ -3438,55 +3426,53 @@
      * Helper action to add a view tag with RemoteInputs.
      */
     private static class SetRemoteInputsAction extends Action {
+        final Parcelable[] mRemoteInputs;
 
         public SetRemoteInputsAction(@IdRes int viewId, RemoteInput[] remoteInputs) {
-            this.viewId = viewId;
-            this.remoteInputs = remoteInputs;
+            this.mViewId = viewId;
+            this.mRemoteInputs = remoteInputs;
         }
 
         public SetRemoteInputsAction(Parcel parcel) {
-            viewId = parcel.readInt();
-            remoteInputs = parcel.createTypedArray(RemoteInput.CREATOR);
+            mViewId = parcel.readInt();
+            mRemoteInputs = parcel.createTypedArray(RemoteInput.CREATOR);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
-            dest.writeTypedArray(remoteInputs, flags);
+            dest.writeInt(mViewId);
+            dest.writeTypedArray(mRemoteInputs, flags);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
-            target.setTagInternal(R.id.remote_input_tag, remoteInputs);
+            target.setTagInternal(R.id.remote_input_tag, mRemoteInputs);
         }
 
         @Override
         public int getActionTag() {
             return SET_REMOTE_INPUTS_ACTION_TAG;
         }
-
-        final Parcelable[] remoteInputs;
     }
 
     /**
      * Helper action to override all textViewColors
      */
     private static class OverrideTextColorsAction extends Action {
-
-        private final int textColor;
+        private final int mTextColor;
 
         public OverrideTextColorsAction(int textColor) {
-            this.textColor = textColor;
+            this.mTextColor = textColor;
         }
 
         public OverrideTextColorsAction(Parcel parcel) {
-            textColor = parcel.readInt();
+            mTextColor = parcel.readInt();
         }
 
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(textColor);
+            dest.writeInt(mTextColor);
         }
 
         @Override
@@ -3499,7 +3485,7 @@
                 if (v instanceof TextView) {
                     TextView textView = (TextView) v;
                     textView.setText(ContrastColorUtil.clearColorSpans(textView.getText()));
-                    textView.setTextColor(textColor);
+                    textView.setTextColor(mTextColor);
                 }
                 if (v instanceof ViewGroup) {
                     ViewGroup viewGroup = (ViewGroup) v;
@@ -3554,34 +3540,33 @@
     }
 
     private static class SetCompoundButtonCheckedAction extends Action {
-
         private final boolean mChecked;
 
         SetCompoundButtonCheckedAction(@IdRes int viewId, boolean checked) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             mChecked = checked;
         }
 
         SetCompoundButtonCheckedAction(Parcel in) {
-            viewId = in.readInt();
+            mViewId = in.readInt();
             mChecked = in.readBoolean();
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             dest.writeBoolean(mChecked);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params)
                 throws ActionException {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             if (!(target instanceof CompoundButton)) {
                 Log.w(LOG_TAG, "Cannot set checked to view "
-                        + viewId + " because it is not a CompoundButton");
+                        + mViewId + " because it is not a CompoundButton");
                 return;
             }
 
@@ -3605,33 +3590,32 @@
     }
 
     private static class SetRadioGroupCheckedAction extends Action {
-
         @IdRes private final int mCheckedId;
 
         SetRadioGroupCheckedAction(@IdRes int viewId, @IdRes int checkedId) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             mCheckedId = checkedId;
         }
 
         SetRadioGroupCheckedAction(Parcel in) {
-            viewId = in.readInt();
+            mViewId = in.readInt();
             mCheckedId = in.readInt();
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             dest.writeInt(mCheckedId);
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params)
                 throws ActionException {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             if (!(target instanceof RadioGroup)) {
-                Log.w(LOG_TAG, "Cannot check " + viewId + " because it's not a RadioGroup");
+                Log.w(LOG_TAG, "Cannot check " + mViewId + " because it's not a RadioGroup");
                 return;
             }
 
@@ -3670,35 +3654,34 @@
     }
 
     private static class SetViewOutlinePreferredRadiusAction extends Action {
-
         @ValueType
         private final int mValueType;
         private final int mValue;
 
         SetViewOutlinePreferredRadiusAction(@IdRes int viewId, int value,
                 @ValueType int valueType) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             this.mValueType = valueType;
             this.mValue = value;
         }
 
         SetViewOutlinePreferredRadiusAction(
                 @IdRes int viewId, float radius, @ComplexDimensionUnit int units) {
-            this.viewId = viewId;
+            this.mViewId = viewId;
             this.mValueType = VALUE_TYPE_COMPLEX_UNIT;
             this.mValue = TypedValue.createComplexDimension(radius, units);
 
         }
 
         SetViewOutlinePreferredRadiusAction(Parcel in) {
-            viewId = in.readInt();
+            mViewId = in.readInt();
             mValueType = in.readInt();
             mValue = in.readInt();
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(viewId);
+            dest.writeInt(mViewId);
             dest.writeInt(mValueType);
             dest.writeInt(mValue);
         }
@@ -3706,7 +3689,7 @@
         @Override
         public void apply(View root, ViewGroup rootParent, ActionApplyParams params)
                 throws ActionException {
-            final View target = root.findViewById(viewId);
+            final View target = root.findViewById(mViewId);
             if (target == null) return;
 
             try {
@@ -3748,7 +3731,6 @@
      * {@link #setViewOutlinePreferredRadius(int, float, int)}.
      */
     public static final class RemoteViewOutlineProvider extends ViewOutlineProvider {
-
         private final float mRadius;
 
         public RemoteViewOutlineProvider(float radius) {
@@ -3821,7 +3803,8 @@
         return mSizedRemoteViews != null;
     }
 
-    private @Nullable SizeF getIdealSize() {
+    @Nullable
+    private SizeF getIdealSize() {
         return mIdealSize;
     }
 
@@ -4174,7 +4157,7 @@
             default:
                 throw new ActionException("Tag " + tag + " not found");
         }
-    };
+    }
 
     /**
      * Returns a deep copy of the RemoteViews object. The RemoteView may not be
@@ -5907,7 +5890,7 @@
          * Callback when the RemoteView has finished inflating,
          * but no actions have been applied yet.
          */
-        default void onViewInflated(View v) {};
+        default void onViewInflated(View v) {}
 
         void onViewApplied(View v);
 
@@ -6288,7 +6271,6 @@
      * @hide
      */
     public class ActionApplyParams {
-
         public InteractionHandler handler;
         public ColorResources colorResources;
         public Executor executor;
@@ -6575,15 +6557,17 @@
     /**
      * Parcelable.Creator that instantiates RemoteViews objects
      */
-    public static final @android.annotation.NonNull Parcelable.Creator<RemoteViews> CREATOR = new Parcelable.Creator<RemoteViews>() {
-        public RemoteViews createFromParcel(Parcel parcel) {
-            return new RemoteViews(parcel);
-        }
+    @NonNull
+    public static final Parcelable.Creator<RemoteViews> CREATOR =
+            new Parcelable.Creator<RemoteViews>() {
+                public RemoteViews createFromParcel(Parcel parcel) {
+                    return new RemoteViews(parcel);
+                }
 
-        public RemoteViews[] newArray(int size) {
-            return new RemoteViews[size];
-        }
-    };
+                public RemoteViews[] newArray(int size) {
+                    return new RemoteViews[size];
+                }
+            };
 
     /**
      * A representation of the view hierarchy. Only views which have a valid ID are added
@@ -7284,7 +7268,8 @@
      * Get the ID of the top-level view of the XML layout, if set using
      * {@link RemoteViews#RemoteViews(String, int, int)}.
      */
-    public @IdRes int getViewId() {
+    @IdRes
+    public int getViewId() {
         return mViewId;
     }
 
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index e0e72ba..a1ebde7 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -47,8 +47,8 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AnimationUtils;
+import android.view.flags.Flags;
 import android.view.inspector.InspectableProperty;
-import android.widget.flags.Flags;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -1011,14 +1011,14 @@
                     if (newScrollY != oldScrollY) {
                         super.scrollTo(mScrollX, newScrollY);
                         if (hitLimit) {
-                            if (Flags.platformWidgetHapticScrollFeedback()) {
+                            if (Flags.scrollFeedbackApi()) {
                                 initHapticScrollFeedbackProviderIfNotExists();
                                 mHapticScrollFeedbackProvider.onScrollLimit(
                                         event.getDeviceId(), event.getSource(), axis,
                                         /* isStart= */ newScrollY == 0);
                             }
                         } else {
-                            if (Flags.platformWidgetHapticScrollFeedback()) {
+                            if (Flags.scrollFeedbackApi()) {
                                 initHapticScrollFeedbackProviderIfNotExists();
                                 mHapticScrollFeedbackProvider.onScrollProgress(
                                         event.getDeviceId(), event.getSource(), axis, delta);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2c41330..e8281ea 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -567,6 +567,8 @@
     private float mShadowDy;
     private int mShadowColor;
 
+    private int mLastOrientation;
+
     private boolean mPreDrawRegistered;
     private boolean mPreDrawListenerDetached;
 
@@ -1193,6 +1195,7 @@
         mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
         mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
         mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
+        mLastOrientation = getResources().getConfiguration().orientation;
 
         final Resources.Theme theme = context.getTheme();
 
@@ -4591,6 +4594,15 @@
             mFontWeightAdjustment = newConfig.fontWeightAdjustment;
             setTypeface(getTypeface());
         }
+
+        InputMethodManager imm = getInputMethodManager();
+        // if orientation changed and this TextView is currently served.
+        if (mLastOrientation != newConfig.orientation
+                && imm != null && imm.hasActiveInputConnection(this)) {
+            // EditorInfo.internalImeOptions are out of date.
+            imm.restartInput(this);
+        }
+        mLastOrientation = newConfig.orientation;
     }
 
     /**
diff --git a/core/java/android/widget/flags/differential_motion_fling_flags.aconfig b/core/java/android/widget/flags/differential_motion_fling_flags.aconfig
new file mode 100644
index 0000000..79cfe56
--- /dev/null
+++ b/core/java/android/widget/flags/differential_motion_fling_flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.widget.flags"
+
+flag {
+    namespace: "toolkit"
+    name: "enable_platform_widget_differential_motion_fling"
+    description: "Enables differential motion fling in platform widgets"
+    bug: "293332089"
+}
\ No newline at end of file
diff --git a/core/java/android/widget/flags/scroll_view_flags.aconfig b/core/java/android/widget/flags/scroll_view_flags.aconfig
deleted file mode 100644
index f93ade2..0000000
--- a/core/java/android/widget/flags/scroll_view_flags.aconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-package: "android.widget.flags"
-
-flag {
-    namespace: "widget"
-    name: "platform_widget_haptic_scroll_feedback"
-    description: "Enables haptic scroll feedback in platform widgets"
-    bug: "287914819"
-}
\ No newline at end of file
diff --git a/core/java/android/window/IRemoteTransition.aidl b/core/java/android/window/IRemoteTransition.aidl
index 2efb68a..ec8b66d 100644
--- a/core/java/android/window/IRemoteTransition.aidl
+++ b/core/java/android/window/IRemoteTransition.aidl
@@ -59,4 +59,12 @@
     void mergeAnimation(in IBinder transition, in TransitionInfo info,
             in SurfaceControl.Transaction t, in IBinder mergeTarget,
             in IRemoteTransitionFinishedCallback finishCallback);
+
+    /**
+     * Called when a different handler has consumed the transition
+     *
+     * @param transition An identifier for the transition that was consumed.
+     * @param aborted Whether the transition is aborted or not.
+     */
+    void onTransitionConsumed(in IBinder transition, in boolean aborted);
 }
diff --git a/core/java/android/window/SystemPerformanceHinter.java b/core/java/android/window/SystemPerformanceHinter.java
new file mode 100644
index 0000000..07ac292
--- /dev/null
+++ b/core/java/android/window/SystemPerformanceHinter.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2023 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.window;
+
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT;
+import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
+import static android.view.SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN;
+import static android.view.SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_SELF;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.PerformanceHintManager;
+import android.os.Trace;
+import android.util.Log;
+import android.view.SurfaceControl;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Random;
+import java.util.function.Supplier;
+
+/**
+ * A helper class to manage performance related hints for a process.  This helper is used for both
+ * long-lived and transient hints.
+ *
+ * @hide
+ */
+public class SystemPerformanceHinter {
+    private static final String TAG = "SystemPerformanceHinter";
+
+    // Change app and SF wakeup times to allow sf more time to composite a frame
+    public static final int HINT_SF_EARLY_WAKEUP = 1 << 0;
+    // Force max refresh rate
+    public static final int HINT_SF_FRAME_RATE = 1 << 1;
+    // Boost CPU & GPU clocks
+    public static final int HINT_ADPF = 1 << 2;
+    // Convenience constant for SF only flags
+    public static final int HINT_SF = HINT_SF_EARLY_WAKEUP | HINT_SF_FRAME_RATE;
+    // Convenience constant for all the flags
+    public static final int HINT_ALL = HINT_SF_EARLY_WAKEUP | HINT_SF_FRAME_RATE | HINT_ADPF;
+
+    // Hints that are applied per-display and require a display root surface
+    private static final int HINT_PER_DISPLAY = HINT_SF_FRAME_RATE;
+    // Hints that are global (not per-display)
+    private static final int HINT_GLOBAL = HINT_SF_EARLY_WAKEUP | HINT_ADPF;
+
+    @IntDef(prefix = {"HINT_"}, value = {
+            HINT_SF_EARLY_WAKEUP,
+            HINT_SF_FRAME_RATE,
+            HINT_ADPF,
+    })
+    private @interface HintFlags {}
+
+    /**
+     * A provider for the root to apply SurfaceControl hints which will be inherited by all children
+     * of that root.
+     * @hide
+     */
+    public interface DisplayRootProvider {
+        /**
+         * @return the SurfaceControl to apply hints for the given displayId.
+         */
+        @Nullable SurfaceControl getRootForDisplay(int displayId);
+    }
+
+    /**
+     * A session where high performance is needed.
+     * @hide
+     */
+    public class HighPerfSession implements AutoCloseable {
+        private final @HintFlags int hintFlags;
+        private final String reason;
+        private final int displayId;
+        private final int traceCookie;
+
+        protected HighPerfSession(@HintFlags int hintFlags, int displayId, @NonNull String reason) {
+            this.hintFlags = hintFlags;
+            this.reason = reason;
+            this.displayId = displayId;
+            this.traceCookie = new Random().nextInt();
+            if (hintFlags != 0) {
+                startSession(this);
+            }
+        }
+
+        /**
+         * Closes this session.
+         */
+        public void close() {
+            if (hintFlags != 0) {
+                endSession(this);
+            }
+        }
+
+        public void finalize() {
+            close();
+        }
+    }
+
+    /**
+     * A no-op implementation of a session.
+     */
+    private class NoOpHighPerfSession extends HighPerfSession {
+        public NoOpHighPerfSession() {
+            super(0 /* hintFlags */, -1 /* displayId */, "");
+        }
+
+        public void close() {
+            // Do nothing
+        }
+    }
+
+    // The active sessions
+    private final ArrayList<HighPerfSession> mActiveSessions = new ArrayList<>();
+    private final SurfaceControl.Transaction mTransaction;
+    private final PerformanceHintManager mPerfHintManager;
+    private @Nullable PerformanceHintManager.Session mAdpfSession;
+    private @Nullable DisplayRootProvider mDisplayRootProvider;
+
+
+    /**
+     * Constructor for the hinter.
+     * @hide
+     */
+    public SystemPerformanceHinter(@NonNull Context context,
+            @Nullable DisplayRootProvider displayRootProvider) {
+        this(context, displayRootProvider, null /* transactionSupplier */);
+    }
+
+    /**
+     * Constructor for the hinter.
+     * @hide
+     */
+    public SystemPerformanceHinter(@NonNull Context context,
+            @Nullable DisplayRootProvider displayRootProvider,
+            @Nullable Supplier<SurfaceControl.Transaction> transactionSupplier) {
+        mDisplayRootProvider = displayRootProvider;
+        mPerfHintManager = context.getSystemService(PerformanceHintManager.class);
+        mTransaction = transactionSupplier != null
+                ? transactionSupplier.get()
+                : new SurfaceControl.Transaction();
+    }
+
+    /**
+     * Sets the current ADPF session, required if you are using HINT_ADPF.  It is the responsibility
+     * of the caller to manage up the ADPF session.
+     * @hide
+     */
+    public void setAdpfSession(PerformanceHintManager.Session adpfSession) {
+        mAdpfSession = adpfSession;
+    }
+
+    /**
+     * Starts a session that requires high performance.
+     * @hide
+     */
+    public HighPerfSession startSession(@HintFlags int hintFlags, int displayId,
+            @NonNull String reason) {
+        if (mDisplayRootProvider == null && (hintFlags & HINT_SF_FRAME_RATE) != 0) {
+            throw new IllegalArgumentException(
+                    "Using SF frame rate hints requires a valid display root provider");
+        }
+        if (mAdpfSession == null && (hintFlags & HINT_ADPF) != 0) {
+            throw new IllegalArgumentException("Using ADPF hints requires an ADPF session");
+        }
+        if ((hintFlags & HINT_PER_DISPLAY) != 0) {
+            if (mDisplayRootProvider.getRootForDisplay(displayId) == null) {
+                // Just log an error and return early if there is no root as there could be races
+                // between when a display root is removed and when a hint session is requested
+                Log.v(TAG, "No display root for displayId=" + displayId);
+                Trace.instant(TRACE_TAG_WINDOW_MANAGER, "PerfHint-NoDisplayRoot: " + displayId);
+                return new NoOpHighPerfSession();
+            }
+        }
+        return new HighPerfSession(hintFlags, displayId, reason);
+    }
+
+    /**
+     * Starts a session that requires high performance.
+     */
+    private void startSession(HighPerfSession session) {
+        int oldGlobalFlags = calculateActiveHintFlags(HINT_GLOBAL);
+        int oldPerDisplayFlags = calculateActiveHintFlagsForDisplay(HINT_PER_DISPLAY,
+                session.displayId);
+        mActiveSessions.add(session);
+        int newGlobalFlags = calculateActiveHintFlags(HINT_GLOBAL);
+        int newPerDisplayFlags = calculateActiveHintFlagsForDisplay(HINT_PER_DISPLAY,
+                session.displayId);
+
+        boolean transactionChanged = false;
+        // Per-display flags
+        if (nowEnabled(oldPerDisplayFlags, newPerDisplayFlags, HINT_SF_FRAME_RATE)) {
+            SurfaceControl displaySurfaceControl = mDisplayRootProvider.getRootForDisplay(
+                    session.displayId);
+            mTransaction.setFrameRateSelectionStrategy(displaySurfaceControl,
+                    FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN);
+            mTransaction.setFrameRateCategory(displaySurfaceControl, FRAME_RATE_CATEGORY_HIGH);
+            transactionChanged = true;
+            Trace.beginAsyncSection("PerfHint-framerate-" + session.displayId + "-"
+                    + session.reason, session.traceCookie);
+        }
+
+        // Global flags
+        if (nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_SF_EARLY_WAKEUP)) {
+            mTransaction.setEarlyWakeupStart();
+            transactionChanged = true;
+            Trace.beginAsyncSection("PerfHint-early_wakeup-" + session.reason, session.traceCookie);
+        }
+        if (nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
+            mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_UP);
+            Trace.beginAsyncSection("PerfHint-adpf-" + session.reason, session.traceCookie);
+        }
+        if (transactionChanged) {
+            mTransaction.applyAsyncUnsafe();
+        }
+    }
+
+    /**
+     * Ends a session that requires high performance.
+     */
+    private void endSession(HighPerfSession session) {
+        int oldGlobalFlags = calculateActiveHintFlags(HINT_GLOBAL);
+        int oldPerDisplayFlags = calculateActiveHintFlagsForDisplay(HINT_PER_DISPLAY,
+                session.displayId);
+        mActiveSessions.remove(session);
+        int newGlobalFlags = calculateActiveHintFlags(HINT_GLOBAL);
+        int newPerDisplayFlags = calculateActiveHintFlagsForDisplay(HINT_PER_DISPLAY,
+                session.displayId);
+
+        boolean transactionChanged = false;
+        // Per-display flags
+        if (nowDisabled(oldPerDisplayFlags, newPerDisplayFlags, HINT_SF_FRAME_RATE)) {
+            SurfaceControl displaySurfaceControl = mDisplayRootProvider.getRootForDisplay(
+                    session.displayId);
+            mTransaction.setFrameRateSelectionStrategy(displaySurfaceControl,
+                    FRAME_RATE_SELECTION_STRATEGY_SELF);
+            mTransaction.setFrameRateCategory(displaySurfaceControl, FRAME_RATE_CATEGORY_DEFAULT);
+            transactionChanged = true;
+            Trace.endAsyncSection("PerfHint-framerate-" + session.displayId + "-" + session.reason,
+                    session.traceCookie);
+        }
+
+        // Global flags
+        if (nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_SF_EARLY_WAKEUP)) {
+            mTransaction.setEarlyWakeupEnd();
+            transactionChanged = true;
+            Trace.endAsyncSection("PerfHint-early_wakeup-" + session.reason, session.traceCookie);
+        }
+        if (nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
+            mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
+            Trace.endAsyncSection("PerfHint-adpf-" + session.reason, session.traceCookie);
+        }
+        if (transactionChanged) {
+            mTransaction.applyAsyncUnsafe();
+        }
+    }
+
+    /**
+     * Checks if checkFlags was previously not set and is now set.
+     */
+    private boolean nowEnabled(@HintFlags int oldFlags, @HintFlags int newFlags,
+                               @HintFlags int checkFlags) {
+        return (oldFlags & checkFlags) == 0 && (newFlags & checkFlags) != 0;
+    }
+
+    /**
+     * Checks if checkFlags was previously set and is now not set.
+     */
+    private boolean nowDisabled(@HintFlags int oldFlags, @HintFlags int newFlags,
+                                @HintFlags int checkFlags) {
+        return (oldFlags & checkFlags) != 0 && (newFlags & checkFlags) == 0;
+    }
+
+    /**
+     * @return the combined hint flags for all active sessions, filtered by {@param filterFlags}.
+     */
+    private @HintFlags int calculateActiveHintFlags(@HintFlags int filterFlags) {
+        int flags = 0;
+        for (int i = 0; i < mActiveSessions.size(); i++) {
+            flags |= mActiveSessions.get(i).hintFlags & filterFlags;
+        }
+        return flags;
+    }
+
+    /**
+     * @return the combined hint flags for all active sessions for a given display, filtered by
+     *         {@param filterFlags}.
+     */
+    private @HintFlags int calculateActiveHintFlagsForDisplay(@HintFlags int filterFlags,
+            int displayId) {
+        int flags = 0;
+        for (int i = 0; i < mActiveSessions.size(); i++) {
+            final HighPerfSession session = mActiveSessions.get(i);
+            if (session.displayId == displayId) {
+                flags |= mActiveSessions.get(i).hintFlags & filterFlags;
+            }
+        }
+        return flags;
+    }
+
+    /**
+     * Dumps the existing sessions.
+     */
+    public void dump(PrintWriter pw, String prefix) {
+        final String innerPrefix = prefix + "  ";
+        pw.println(prefix + TAG + ":");
+        pw.println(innerPrefix + "Active sessions (" + mActiveSessions.size() + "):");
+        for (int i = 0; i < mActiveSessions.size(); i++) {
+            final HighPerfSession s = mActiveSessions.get(i);
+            pw.println(innerPrefix + "  reason=" + s.reason
+                    + " flags=" + s.hintFlags
+                    + " display=" + s.displayId);
+        }
+    }
+}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 3323ae5..c2b5196 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -897,6 +897,23 @@
     }
 
     /**
+     * Moves the PiP activity of a parent task to a pinned root task.
+     * @param parentToken the parent task of the PiP activity
+     * @param bounds the entry bounds
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction movePipActivityToPinnedRootTask(
+            @NonNull WindowContainerToken parentToken, @NonNull Rect bounds) {
+        mHierarchyOps.add(new HierarchyOp
+                .Builder(HierarchyOp.HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK)
+                .setContainer(parentToken.asBinder())
+                .setBounds(bounds)
+                .build());
+        return this;
+    }
+
+    /**
      * Merges another WCT into this one.
      * @param transfer When true, this will transfer everything from other potentially leaving
      *                 other in an unusable state. When false, other is left alone, but
@@ -1327,6 +1344,7 @@
         public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 15;
         public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 16;
         public static final int HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION = 17;
+        public static final int HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK = 18;
 
         // The following key(s) are for use with mLaunchOptions:
         // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1379,6 +1397,9 @@
         @Nullable
         private ShortcutInfo mShortcutInfo;
 
+        @Nullable
+        private Rect mBounds;
+
         private boolean mAlwaysOnTop;
 
         private boolean mReparentLeafTaskIfRelaunch;
@@ -1482,6 +1503,7 @@
         public HierarchyOp(@NonNull HierarchyOp copy) {
             mType = copy.mType;
             mContainer = copy.mContainer;
+            mBounds = copy.mBounds;
             mReparent = copy.mReparent;
             mInsetsFrameProvider = copy.mInsetsFrameProvider;
             mInsetsFrameOwner = copy.mInsetsFrameOwner;
@@ -1501,6 +1523,7 @@
         protected HierarchyOp(Parcel in) {
             mType = in.readInt();
             mContainer = in.readStrongBinder();
+            mBounds = in.readTypedObject(Rect.CREATOR);
             mReparent = in.readStrongBinder();
             mInsetsFrameProvider = in.readTypedObject(InsetsFrameProvider.CREATOR);
             mInsetsFrameOwner = in.readStrongBinder();
@@ -1599,6 +1622,11 @@
             return mShortcutInfo;
         }
 
+        @NonNull
+        public Rect getBounds() {
+            return mBounds;
+        }
+
         /** Gets a string representation of a hierarchy-op type. */
         public static String hopToString(int type) {
             switch (type) {
@@ -1709,6 +1737,7 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mType);
             dest.writeStrongBinder(mContainer);
+            dest.writeTypedObject(mBounds, flags);
             dest.writeStrongBinder(mReparent);
             dest.writeTypedObject(mInsetsFrameProvider, flags);
             dest.writeStrongBinder(mInsetsFrameOwner);
@@ -1783,6 +1812,9 @@
             @Nullable
             private ShortcutInfo mShortcutInfo;
 
+            @Nullable
+            private Rect mBounds;
+
             private boolean mAlwaysOnTop;
 
             private boolean mReparentLeafTaskIfRelaunch;
@@ -1867,6 +1899,11 @@
                 return this;
             }
 
+            Builder setBounds(@NonNull Rect bounds) {
+                mBounds = bounds;
+                return this;
+            }
+
             HierarchyOp build() {
                 final HierarchyOp hierarchyOp = new HierarchyOp(mType);
                 hierarchyOp.mContainer = mContainer;
@@ -1887,6 +1924,7 @@
                 hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
                 hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation;
                 hierarchyOp.mShortcutInfo = mShortcutInfo;
+                hierarchyOp.mBounds = mBounds;
                 hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch;
 
                 return hierarchyOp;
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 0ee07bb..3d4bc2f 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -16,9 +16,6 @@
 
 package android.window;
 
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -37,8 +34,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+
 import java.io.PrintWriter;
-import java.lang.annotation.Retention;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -60,18 +57,6 @@
  * @hide
  */
 public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
-    @Retention(SOURCE)
-    @IntDef({
-        BACK_CALLBACK_ENABLED,
-        BACK_CALLBACK_DISABLED,
-        BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS
-    })
-    public @interface OnBackInvokedCallbackType {}
-
-    public static final int BACK_CALLBACK_ENABLED = 0;
-    public static final int BACK_CALLBACK_DISABLED = 1;
-    public static final int BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS = 2;
-
     private IWindowSession mWindowSession;
     private IWindow mWindow;
     private static final String TAG = "WindowOnBackDispatcher";
@@ -283,6 +268,13 @@
     }
 
     /**
+     * Returns false if the legacy back behavior should be used.
+     */
+    public boolean isOnBackInvokedCallbackEnabled() {
+        return Checker.isOnBackInvokedCallbackEnabled(mChecker.getContext());
+    }
+
+    /**
      * Dump information about this WindowOnBackInvokedDispatcher
      * @param prefix the prefix that will be prepended to each line of the produced output
      * @param writer the writer that will receive the resulting text
@@ -395,20 +387,6 @@
         }
     }
 
-    /** Returns false if the legacy back behavior should be used. */
-    public boolean isOnBackInvokedCallbackEnabled() {
-        return isOnBackInvokedCallbackEnabled(mChecker.getContext());
-    }
-
-    /**
-     * Returns true if system gesture exclusion is needed for global gesture compatibility with
-     * windowSwipeToDismiss styleable.
-     */
-    public boolean isSystemGestureExclusionNeeded() {
-        return Checker.getBackCallbackType(mChecker.getContext())
-                == BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS;
-    }
-
     /**
      * Returns false if the legacy back behavior should be used.
      * <p>
@@ -416,7 +394,7 @@
      * {@link OnBackInvokedCallback}.
      */
     public static boolean isOnBackInvokedCallbackEnabled(@NonNull Context context) {
-        return Checker.getBackCallbackType(context) == BACK_CALLBACK_ENABLED;
+        return Checker.isOnBackInvokedCallbackEnabled(context);
     }
 
     @Override
@@ -468,29 +446,28 @@
             return mContext.get();
         }
 
-        @OnBackInvokedCallbackType
-        private static int getBackCallbackType(@Nullable Context context) {
+        private static boolean isOnBackInvokedCallbackEnabled(@Nullable Context context) {
             // new back is enabled if the feature flag is enabled AND the app does not explicitly
             // request legacy back.
             boolean featureFlagEnabled = ENABLE_PREDICTIVE_BACK;
             if (!featureFlagEnabled) {
-                return BACK_CALLBACK_DISABLED;
+                return false;
             }
 
             if (ALWAYS_ENFORCE_PREDICTIVE_BACK) {
-                Log.i(TAG, "getBackCallbackType: always enable");
-                return BACK_CALLBACK_ENABLED;
+                return true;
             }
 
             // If the context is null, return false to use legacy back.
             if (context == null) {
                 Log.w(TAG, "OnBackInvokedCallback is not enabled because context is null.");
-                return BACK_CALLBACK_DISABLED;
+                return false;
             }
 
             boolean requestsPredictiveBack = false;
 
             // Check if the context is from an activity.
+            Context originalContext = context;
             while ((context instanceof ContextWrapper) && !(context instanceof Activity)) {
                 context = ((ContextWrapper) context).getBaseContext();
             }
@@ -539,8 +516,10 @@
                     // 3. windowSwipeToDismiss=false should be respected for apps not opted in,
                     //    which disables PB & onBackPressed caused by BackAnimController's
                     //    setTrigger(true)
+                    // Use the original context to resolve the styled attribute so that they stay
+                    // true to the window.
                     TypedArray windowAttr =
-                            context.obtainStyledAttributes(
+                            originalContext.obtainStyledAttributes(
                                     new int[] {android.R.attr.windowSwipeToDismiss});
                     boolean windowSwipeToDismiss = true;
                     if (windowAttr.getIndexCount() > 0) {
@@ -552,15 +531,11 @@
                         Log.i(TAG, "falling back to windowSwipeToDismiss: " + windowSwipeToDismiss);
                     }
 
-                    if (!windowSwipeToDismiss) {
-                        return BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS;
-                    } else {
-                        return BACK_CALLBACK_ENABLED;
-                    }
+                    requestsPredictiveBack = windowSwipeToDismiss;
                 }
             }
 
-            return requestsPredictiveBack ? BACK_CALLBACK_ENABLED : BACK_CALLBACK_DISABLED;
+            return requestsPredictiveBack;
         }
     }
 }
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
new file mode 100644
index 0000000..ccbf4a9
--- /dev/null
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -0,0 +1,19 @@
+package: "com.android.window.flags"
+
+# Project link: https://gantry.corp.google.com/projects/android_platform_window_surfaces/changes
+
+flag {
+    namespace: "window_surfaces"
+    name: "surface_trusted_overlay"
+    description: "Whether to add trusted overlay flag on the SurfaceControl or the InputWindow"
+    is_fixed_read_only: true
+    bug: "292032926"
+}
+
+flag {
+    namespace: "window_surfaces"
+    name: "explicit_refresh_rate_hints"
+    description: "Performance related hints during transitions"
+    is_fixed_read_only: true
+    bug: "300019131"
+}
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 5dd558a..987c14c 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -28,15 +28,19 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.AlertDialog;
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.view.View;
 import android.view.Window;
+import android.view.WindowManager;
+import android.view.accessibility.Flags;
 import android.widget.AdapterView;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -207,6 +211,11 @@
                 isEditMenuMode ? this::onTargetChecked : this::onTargetSelected);
     }
 
+    @VisibleForTesting
+    public AlertDialog getMenuDialog() {
+        return mMenuDialog;
+    }
+
     private AlertDialog createMenuDialog() {
         final String dialogTitle =
                 getString(R.string.accessibility_select_shortcut_menu_title);
@@ -216,12 +225,25 @@
                 .setAdapter(mTargetAdapter, /* listener= */ null)
                 .setOnDismissListener(dialog -> finish());
 
-        if (isUserSetupCompleted(this)) {
+        boolean allowEditing = isUserSetupCompleted(this);
+        boolean showWhenLocked = false;
+        if (Flags.allowShortcutChooserOnLockscreen()) {
+            final KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
+            if (keyguardManager != null && keyguardManager.isKeyguardLocked()) {
+                allowEditing = false;
+                showWhenLocked = true;
+            }
+        }
+        if (allowEditing) {
             final String positiveButtonText =
                     getString(R.string.edit_accessibility_shortcut_menu_button);
             builder.setPositiveButton(positiveButtonText, /* listener= */ null);
         }
 
-        return builder.create();
+        final AlertDialog dialog = builder.create();
+        if (showWhenLocked) {
+            dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        }
+        return dialog;
     }
 }
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 2909b6a..e494346 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -414,11 +414,6 @@
             "dark_launch_remote_prediction_service_enabled";
 
     /**
-     * (boolean) Whether to enable pinch resizing for PIP.
-     */
-    public static final String PIP_PINCH_RESIZE = "pip_pinch_resize";
-
-    /**
      * (boolean) Whether to enable stashing for PIP.
      */
     public static final String PIP_STASHING = "pip_stashing";
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index cb2d934..b1d22e0 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -86,6 +86,28 @@
         public static final Flag ENABLE_ATTENTION_HELPER_REFACTOR = devFlag(
                 "persist.debug.sysui.notification.enable_attention_helper_refactor");
 
+        // TODO b/291899544: for released flags, use resource config values
+        /** Value used by polite notif. feature */
+        public static final Flag NOTIF_COOLDOWN_T1 = devFlag(
+                "persist.debug.sysui.notification.notif_cooldown_t1", 5000);
+        /** Value used by polite notif. feature */
+        public static final Flag NOTIF_COOLDOWN_T2 = devFlag(
+                "persist.debug.sysui.notification.notif_cooldown_t2", 3000);
+        /** Value used by polite notif. feature */
+        public static final Flag NOTIF_VOLUME1 = devFlag(
+                "persist.debug.sysui.notification.notif_volume1", 30);
+        public static final Flag NOTIF_VOLUME2 = devFlag(
+                "persist.debug.sysui.notification.notif_volume2", 0);
+        /** Value used by polite notif. feature. -1 to ignore the counter */
+        public static final Flag NOTIF_COOLDOWN_COUNTER_RESET = devFlag(
+                "persist.debug.sysui.notification.notif_cooldown_counter_reset", 10);
+        /**
+         * Value used by polite notif. feature: cooldown behavior/strategy. Valid values: rule1,
+         * rule2
+         */
+        public static final Flag NOTIF_COOLDOWN_RULE = devFlag(
+                "persist.debug.sysui.notification.notif_cooldown_rule", "rule1");
+
         /** b/301242692: Visit extra URIs used in notifications to prevent security issues. */
         public static final Flag VISIT_RISKY_URIS = devFlag(
                 "persist.sysui.notification.visit_risky_uris");
@@ -97,6 +119,10 @@
     public interface FlagResolver {
         /** Is the flag enabled? */
         boolean isEnabled(Flag flag);
+        /** Get the flag value (integer) */
+        int getIntValue(Flag flag);
+        /** Get the flag value (string) */
+        String getStringValue(Flag flag);
     }
 
     /** The primary, immutable resolver returned by getResolver() */
@@ -134,6 +160,22 @@
     }
 
     /**
+     * Creates a flag that with a default integer value in debuggable builds.
+     */
+    @VisibleForTesting
+    public static Flag devFlag(String name, int defaultValue) {
+        return new Flag(name, defaultValue, null);
+    }
+
+    /**
+     * Creates a flag that with a default string value in debuggable builds.
+     */
+    @VisibleForTesting
+    public static Flag devFlag(String name, String defaultValue) {
+        return new Flag(name, defaultValue, null);
+    }
+
+    /**
      * Creates a flag that is disabled by default in debuggable builds.
      * It can be enabled or force-disabled by setting this flag's SystemProperty to 1 or 0.
      * If this flag's SystemProperty is not set, the flag can be enabled by setting the
@@ -161,6 +203,8 @@
     public static final class Flag {
         public final String mSysPropKey;
         public final boolean mDefaultValue;
+        public final int mDefaultIntValue;
+        public final String mDefaultStringValue;
         @Nullable
         public final Flag mDebugDefault;
 
@@ -170,6 +214,24 @@
             mSysPropKey = sysPropKey;
             mDefaultValue = defaultValue;
             mDebugDefault = debugDefault;
+            mDefaultIntValue = 0;
+            mDefaultStringValue = null;
+        }
+
+        public Flag(@NonNull String sysPropKey, int defaultValue, @Nullable Flag debugDefault) {
+            mSysPropKey = sysPropKey;
+            mDefaultIntValue = defaultValue;
+            mDebugDefault = debugDefault;
+            mDefaultValue = false;
+            mDefaultStringValue = null;
+        }
+
+        public Flag(@NonNull String sysPropKey, String defaultValue, @Nullable Flag debugDefault) {
+            mSysPropKey = sysPropKey;
+            mDefaultStringValue = defaultValue;
+            mDebugDefault = debugDefault;
+            mDefaultValue = false;
+            mDefaultIntValue = 0;
         }
     }
 
@@ -181,6 +243,16 @@
         public boolean isEnabled(Flag flag) {
             return flag.mDefaultValue;
         }
+
+        @Override
+        public int getIntValue(Flag flag) {
+            return flag.mDefaultIntValue;
+        }
+
+        @Override
+        public String getStringValue(Flag flag) {
+            return flag.mDefaultStringValue;
+        }
     }
 
     /** Implementation of the interface used in debuggable builds. */
@@ -199,5 +271,23 @@
         public boolean getBoolean(String key, boolean defaultValue) {
             return SystemProperties.getBoolean(key, defaultValue);
         }
+
+        /** Look up the value; overridable for tests to avoid needing to set SystemProperties */
+        @VisibleForTesting
+        public int getIntValue(Flag flag) {
+            if (flag.mDebugDefault == null) {
+                return SystemProperties.getInt(flag.mSysPropKey, flag.mDefaultIntValue);
+            }
+            return SystemProperties.getInt(flag.mSysPropKey, getIntValue(flag.mDebugDefault));
+        }
+
+        /** Look up the value; overridable for tests to avoid needing to set SystemProperties */
+        @VisibleForTesting
+        public String getStringValue(Flag flag) {
+            if (flag.mDebugDefault == null) {
+                return SystemProperties.get(flag.mSysPropKey, flag.mDefaultStringValue);
+            }
+            return SystemProperties.get(flag.mSysPropKey, getStringValue(flag.mDebugDefault));
+        }
     }
 }
diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
new file mode 100644
index 0000000..e55c641
--- /dev/null
+++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.display;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.util.Log;
+import android.view.Display;
+
+/**
+ * Constants and utility methods for refresh rate settings.
+ */
+public class RefreshRateSettingsUtils {
+
+    private static final String TAG = "RefreshRateSettingsUtils";
+
+    public static final float DEFAULT_REFRESH_RATE = 60f;
+
+    /**
+     * Find the highest refresh rate among all the modes of the default display.
+     *
+     * @param context The context
+     * @return The highest refresh rate
+     */
+    public static float findHighestRefreshRateForDefaultDisplay(Context context) {
+        final DisplayManager dm = context.getSystemService(DisplayManager.class);
+        final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
+
+        if (display == null) {
+            Log.w(TAG, "No valid default display device");
+            return DEFAULT_REFRESH_RATE;
+        }
+
+        float maxRefreshRate = DEFAULT_REFRESH_RATE;
+        for (Display.Mode mode : display.getSupportedModes()) {
+            if (mode.getRefreshRate() > maxRefreshRate) {
+                maxRefreshRate = mode.getRefreshRate();
+            }
+        }
+        return maxRefreshRate;
+    }
+}
diff --git a/core/java/com/android/internal/foldables/Android.bp b/core/java/com/android/internal/foldables/Android.bp
new file mode 100644
index 0000000..f1d06da
--- /dev/null
+++ b/core/java/com/android/internal/foldables/Android.bp
@@ -0,0 +1,7 @@
+aconfig_declarations {
+    name: "fold_lock_setting_flags",
+    package: "com.android.internal.foldables.flags",
+    srcs: [
+        "fold_lock_setting_flags.aconfig",
+    ],
+}
diff --git a/core/java/com/android/internal/foldables/FoldLockSettingAvailabilityProvider.java b/core/java/com/android/internal/foldables/FoldLockSettingAvailabilityProvider.java
index 4e3888a..a115ecf 100644
--- a/core/java/com/android/internal/foldables/FoldLockSettingAvailabilityProvider.java
+++ b/core/java/com/android/internal/foldables/FoldLockSettingAvailabilityProvider.java
@@ -17,16 +17,23 @@
 package com.android.internal.foldables;
 
 import android.content.res.Resources;
+import android.os.Build;
 import android.sysprop.FoldLockBehaviorProperties;
+import android.util.Slog;
 
 import com.android.internal.R;
+import com.android.internal.foldables.flags.Flags;
+
+import java.util.function.Supplier;
 
 /**
  * Wrapper class to access {@link FoldLockBehaviorProperties} and also assists with testing
  */
 public class FoldLockSettingAvailabilityProvider {
 
-    boolean mFoldLockBehaviorResourceValue;
+    private static final String TAG = "FoldLockSettingAvailabilityProvider";
+    private final boolean mFoldLockBehaviorResourceValue;
+    private final Supplier<Boolean> mFoldLockSettingEnabled = Flags::foldLockSettingEnabled;
 
     public FoldLockSettingAvailabilityProvider(Resources resources) {
         mFoldLockBehaviorResourceValue = resources.getBoolean(
@@ -35,6 +42,22 @@
 
     public boolean isFoldLockBehaviorAvailable() {
         return mFoldLockBehaviorResourceValue
-                && FoldLockBehaviorProperties.fold_lock_setting_enabled().orElse(false);
+                && flagOrSystemProperty();
+    }
+
+    private boolean flagOrSystemProperty() {
+        if ((Build.IS_ENG || Build.IS_USERDEBUG)
+                && FoldLockBehaviorProperties.fold_lock_setting_enabled().orElse(false)) {
+            return true;
+        }
+        try {
+            return mFoldLockSettingEnabled.get();
+        } catch (Throwable ex) {
+            Slog.i(TAG,
+                    "Flags not ready yet. Return false for "
+                            + Flags.FLAG_FOLD_LOCK_SETTING_ENABLED,
+                    ex);
+            return false;
+        }
     }
 }
diff --git a/core/java/com/android/internal/foldables/OWNERS b/core/java/com/android/internal/foldables/OWNERS
new file mode 100644
index 0000000..6ce1ee4
--- /dev/null
+++ b/core/java/com/android/internal/foldables/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/display/OWNERS
diff --git a/core/java/com/android/internal/foldables/fold_lock_setting_flags.aconfig b/core/java/com/android/internal/foldables/fold_lock_setting_flags.aconfig
new file mode 100644
index 0000000..44f436ea
--- /dev/null
+++ b/core/java/com/android/internal/foldables/fold_lock_setting_flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.internal.foldables.flags"
+
+flag {
+    name: "fold_lock_setting_enabled"
+    namespace: "display_manager"
+    description: "Feature flag for Fold Lock Setting"
+    bug: "274447767"
+    is_fixed_read_only: true
+}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 1bfb51c..6e836e0 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -837,25 +837,41 @@
 
     @WorkerThread
     private void updateProperties(DeviceConfig.Properties properties) {
-        mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY,
-                DEFAULT_SAMPLING_INTERVAL);
-        mTraceThresholdMissedFrames = properties.getInt(SETTINGS_THRESHOLD_MISSED_FRAMES_KEY,
-                DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES);
-        mTraceThresholdFrameTimeMillis = properties.getInt(
-                SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY,
-                DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS);
-        // Never allow the debug overlay to be used on user builds
-        boolean debugOverlayEnabled = Build.IS_DEBUGGABLE && properties.getBoolean(
-                SETTINGS_DEBUG_OVERLAY_ENABLED_KEY,
-                DEFAULT_DEBUG_OVERLAY_ENABLED);
-        if (debugOverlayEnabled && mDebugOverlay == null) {
-            mDebugOverlay = new InteractionMonitorDebugOverlay(mLock, mDebugBgColor, mDebugYOffset);
-        } else if (!debugOverlayEnabled && mDebugOverlay != null) {
-            mDebugOverlay.dispose();
-            mDebugOverlay = null;
+        for (String property : properties.getKeyset()) {
+            switch (property) {
+                case SETTINGS_SAMPLING_INTERVAL_KEY:
+                    mSamplingInterval = properties.getInt(property, DEFAULT_SAMPLING_INTERVAL);
+                    break;
+                case SETTINGS_THRESHOLD_MISSED_FRAMES_KEY:
+                    mTraceThresholdMissedFrames =
+                            properties.getInt(property, DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES);
+                    break;
+                case SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY:
+                    mTraceThresholdFrameTimeMillis =
+                            properties.getInt(property, DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS);
+                    break;
+                case SETTINGS_ENABLED_KEY:
+                    mEnabled = properties.getBoolean(property, DEFAULT_ENABLED);
+                    break;
+                case SETTINGS_DEBUG_OVERLAY_ENABLED_KEY:
+                    // Never allow the debug overlay to be used on user builds
+                    boolean debugOverlayEnabled = Build.IS_DEBUGGABLE
+                            && properties.getBoolean(property, DEFAULT_DEBUG_OVERLAY_ENABLED);
+                    if (debugOverlayEnabled && mDebugOverlay == null) {
+                        mDebugOverlay = new InteractionMonitorDebugOverlay(
+                                mLock, mDebugBgColor, mDebugYOffset);
+                    } else if (!debugOverlayEnabled && mDebugOverlay != null) {
+                        mDebugOverlay.dispose();
+                        mDebugOverlay = null;
+                    }
+                    break;
+                default:
+                    if (DEBUG) {
+                        Log.d(TAG, "Got a change event for an unknown property: "
+                                + property + " => " + properties.getString(property, ""));
+                    }
+            }
         }
-        // The memory visibility is powered by the volatile field, mEnabled.
-        mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
     }
 
     @VisibleForTesting
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1be916f..8566263 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -290,11 +290,12 @@
     };
     private Consumer<Boolean> mCrossWindowBlurEnabledListener;
 
+    private final WearGestureInterceptionDetector mWearGestureInterceptionDetector;
+
     DecorView(Context context, int featureId, PhoneWindow window,
             WindowManager.LayoutParams params) {
         super(context);
         mFeatureId = featureId;
-
         mShowInterpolator = AnimationUtils.loadInterpolator(context,
                 android.R.interpolator.linear_out_slow_in);
         mHideInterpolator = AnimationUtils.loadInterpolator(context,
@@ -314,6 +315,11 @@
         updateLogTag(params);
 
         mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK);
+
+        mWearGestureInterceptionDetector =
+                WearGestureInterceptionDetector.isEnabled(context)
+                        ? new WearGestureInterceptionDetector(context, this)
+                        : null;
     }
 
     void setBackgroundFallback(@Nullable Drawable fallbackDrawable) {
@@ -544,6 +550,18 @@
             }
         }
 
+        ViewRootImpl viewRootImpl = getViewRootImpl();
+        if (viewRootImpl != null && mWearGestureInterceptionDetector != null) {
+            boolean wasIntercepting = mWearGestureInterceptionDetector.isIntercepting();
+            boolean intercepting = mWearGestureInterceptionDetector.onInterceptTouchEvent(event);
+            if (wasIntercepting != intercepting) {
+                viewRootImpl.updateDecorViewGestureInterception(intercepting);
+            }
+            if (intercepting) {
+                return true;
+            }
+        }
+
         if (!SWEEP_OPEN_MENU) {
             return false;
         }
diff --git a/core/java/com/android/internal/policy/WearGestureInterceptionDetector.java b/core/java/com/android/internal/policy/WearGestureInterceptionDetector.java
new file mode 100644
index 0000000..6fd5018
--- /dev/null
+++ b/core/java/com/android/internal/policy/WearGestureInterceptionDetector.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2023 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.policy;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.TypedArray;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+/**
+ * Wear-specific gesture interception detector to be installed at DecorView, for compatibility of
+ * apps depending on legacy SwipeDismissLayout behavior.
+ *
+ * <p>Results of the detector will be used by {@code DecorView} to intercept motion events. The
+ * interception state will also be sent to {@code android.view.ViewRootImpl} and {@code
+ * com.android.server.wm.DisplayContent} through {@code android.view.IWindowSession}.
+ *
+ * <p>SystemUI can register {@code android.view.IDecorViewGestureListener} to listen for the result
+ * of the detector. The result will be valid for between a pair of touch down/up events.
+ */
+public class WearGestureInterceptionDetector {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "WearGestureInterceptionDetector";
+
+    private final DecorView mInstalledDecorView;
+    private final float mTouchSlop;
+    private final float mSwipingStartThreshold;
+    private boolean mSwiping;
+
+    private float mDownX;
+    private float mDownY;
+    private int mActivePointerId;
+    private boolean mDiscardIntercept;
+
+    WearGestureInterceptionDetector(Context context, DecorView installedDecorView) {
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mInstalledDecorView = installedDecorView;
+        mSwipingStartThreshold = mTouchSlop * 2;
+    }
+
+    /** Check if this gesture interception detector should be enabled. */
+    public static boolean isEnabled(Context context) {
+        PackageManager pm = context.getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            return false;
+        }
+
+        // Compatibility check for flag that disables legacy SwipeDismissLayout.
+        TypedArray windowAttr =
+                context.obtainStyledAttributes(new int[] {android.R.attr.windowSwipeToDismiss});
+        boolean windowSwipeToDismiss = true;
+        if (windowAttr.getIndexCount() > 0) {
+            windowSwipeToDismiss = windowAttr.getBoolean(0, true);
+        }
+        windowAttr.recycle();
+        return windowSwipeToDismiss;
+    }
+
+    private boolean isPointerIndexValid(MotionEvent ev) {
+        int pointerIndex = ev.findPointerIndex(mActivePointerId);
+        if (pointerIndex == -1) {
+            if (DEBUG) {
+                Log.e(TAG, "Invalid pointer index: ignoring.");
+            }
+            mDiscardIntercept = true;
+            return false;
+        }
+        return true;
+    }
+
+    private void updateSwiping(MotionEvent ev) {
+        if (mSwiping) {
+            return;
+        }
+        float deltaX = ev.getRawX() - mDownX;
+        float deltaY = ev.getRawY() - mDownY;
+        // Check if we have left the touch slop area.
+        if ((deltaX * deltaX) + (deltaY * deltaY) > (mTouchSlop * mTouchSlop)) {
+            mSwiping = deltaX > mSwipingStartThreshold && Math.abs(deltaY) < Math.abs(deltaX);
+        }
+    }
+
+    private void updateDiscardIntercept(MotionEvent ev) {
+        if (!mSwiping) {
+            // Don't look at canScroll until we have passed the touch slop
+            return;
+        }
+        if (mDiscardIntercept) {
+            return;
+        }
+        final boolean checkLeft = mDownX < ev.getRawX();
+        final float x = ev.getX(mActivePointerId);
+        final float y = ev.getY(mActivePointerId);
+        if (canScroll(mInstalledDecorView, false, checkLeft, x, y)) {
+            mDiscardIntercept = true;
+        }
+    }
+
+    /** Resets internal members when canceling. */
+    private void resetMembers() {
+        mDownX = 0;
+        mDownY = 0;
+        mSwiping = false;
+        mDiscardIntercept = false;
+    }
+
+    /** Should we intercept the MotionEvent for system gesture? */
+    public boolean isIntercepting() {
+        return !mDiscardIntercept && mSwiping;
+    }
+
+    /** Tests if the MotionEvent should be intercepted */
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                resetMembers();
+                mDownX = ev.getRawX();
+                mDownY = ev.getRawY();
+                mActivePointerId = ev.getPointerId(0);
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+                mActivePointerId = ev.getPointerId(ev.getActionIndex());
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                int associatedPointerIndex = ev.getActionIndex();
+                if (ev.getPointerId(associatedPointerIndex) == mActivePointerId) {
+                    // This was our active pointer going up.
+                    // Choose the first available pointer index.
+                    int newActionIndex = associatedPointerIndex == 0 ? 1 : 0;
+                    mActivePointerId = ev.getPointerId(newActionIndex);
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mDiscardIntercept) {
+                    break;
+                }
+                if (!isPointerIndexValid(ev)) {
+                    break;
+                }
+                updateSwiping(ev);
+                updateDiscardIntercept(ev);
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                resetMembers();
+                break;
+        }
+        return isIntercepting();
+    }
+
+    /**
+     * Tests scroll-ability within child views of v in the direction of dx.
+     *
+     * @param v View to test for horizontal scroll-ability
+     * @param checkSelf Whether the view v passed should itself be checked for scroll-ability
+     *     (true), or just its children (false).
+     * @param checkLeft Which direction to check? Left = true, right = false.
+     * @param x X coordinate of the active touch point
+     * @param y Y coordinate of the active touch point
+     * @return true if child views of v can be scrolled by delta of dx.
+     */
+    private boolean canScroll(View v, boolean checkSelf, boolean checkLeft, float x, float y) {
+        if (v instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) v;
+            final int scrollX = v.getScrollX();
+            final int scrollY = v.getScrollY();
+            final int count = group.getChildCount();
+            for (int i = count - 1; i >= 0; i--) {
+                final View child = group.getChildAt(i);
+
+                if (x + scrollX < child.getLeft()
+                        || x + scrollX >= child.getRight()
+                        || y + scrollY < child.getTop()
+                        || y + scrollY >= child.getBottom()) {
+                    // This child is out of bound, don't bother checking.
+                    continue;
+                }
+
+                // Recursively check until finding the first scrollable or none is scrollable.
+                if (canScroll(
+                        /* view= */ child,
+                        /* checkSelf= */ true,
+                        /* checkLeft= */ checkLeft,
+                        /* x= */ x + scrollX - child.getLeft(),
+                        /* y= */ y + scrollY - child.getTop())) {
+                    return true;
+                }
+            }
+        }
+
+        return checkSelf && v.canScrollHorizontally(checkLeft ? -1 : 1);
+    }
+}
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 06e69f2..fd435d0 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -222,6 +222,7 @@
     private boolean isContentRectWithinBounds() {
         mContext.getDisplayNoVerify().getRealSize(mDisplaySize);
         mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
+        mScreenRect.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]);
 
         return intersectsClosed(mContentRectOnScreen, mScreenRect)
             && intersectsClosed(mContentRectOnScreen, mViewRectOnScreen);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9384f41..ba644eb 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -127,6 +127,7 @@
     jfieldID xDpi;
     jfieldID yDpi;
     jfieldID refreshRate;
+    jfieldID vsyncRate;
     jfieldID appVsyncOffsetNanos;
     jfieldID presentationDeadlineNanos;
     jfieldID group;
@@ -469,9 +470,10 @@
     }
 }
 
-static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
+static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync,
+                                   jboolean oneWay) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-    transaction->apply(sync);
+    transaction->apply(sync, oneWay);
 }
 
 static void nativeMergeTransaction(JNIEnv* env, jclass clazz,
@@ -1230,6 +1232,7 @@
     env->SetFloatField(object, gDisplayModeClassInfo.yDpi, config.yDpi);
 
     env->SetFloatField(object, gDisplayModeClassInfo.refreshRate, config.refreshRate);
+    env->SetFloatField(object, gDisplayModeClassInfo.vsyncRate, config.vsyncRate);
     env->SetLongField(object, gDisplayModeClassInfo.appVsyncOffsetNanos, config.appVsyncOffset);
     env->SetLongField(object, gDisplayModeClassInfo.presentationDeadlineNanos,
                       config.presentationDeadline);
@@ -2119,7 +2122,7 @@
             (void*)nativeSetDefaultBufferSize},
     {"nativeCreateTransaction", "()J",
             (void*)nativeCreateTransaction },
-    {"nativeApplyTransaction", "(JZ)V",
+    {"nativeApplyTransaction", "(JZZ)V",
             (void*)nativeApplyTransaction },
     {"nativeGetNativeTransactionFinalizer", "()J",
             (void*)nativeGetNativeTransactionFinalizer },
@@ -2393,6 +2396,7 @@
     gDisplayModeClassInfo.xDpi = GetFieldIDOrDie(env, modeClazz, "xDpi", "F");
     gDisplayModeClassInfo.yDpi = GetFieldIDOrDie(env, modeClazz, "yDpi", "F");
     gDisplayModeClassInfo.refreshRate = GetFieldIDOrDie(env, modeClazz, "refreshRate", "F");
+    gDisplayModeClassInfo.vsyncRate = GetFieldIDOrDie(env, modeClazz, "vsyncRate", "F");
     gDisplayModeClassInfo.appVsyncOffsetNanos =
             GetFieldIDOrDie(env, modeClazz, "appVsyncOffsetNanos", "J");
     gDisplayModeClassInfo.presentationDeadlineNanos =
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6c93680..4732702 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -98,6 +98,7 @@
         // Settings for font scaling
         optional SettingProto accessibility_font_scaling_has_been_changed = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_force_invert_color_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto accessibility_magnification_gesture = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e34e423..b0ecc60 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -48,6 +48,7 @@
     <protected-broadcast android:name="android.intent.action.CANCEL_ENABLE_ROLLBACK" />
     <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_UNSTOPPED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION" />
@@ -7232,6 +7233,15 @@
                 android:description="@string/permdesc_fullScreenIntent"
                 android:protectionLevel="normal|appop" />
 
+    <!-- @SystemApi Required for the privileged assistant apps targeting
+         {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
+         that receive voice trigger from the trusted hotword detection service.
+         <p>Protection level: signature|privileged|appop
+         @FlaggedApi("android.permission.flags.voice_activation_permission_apis")
+         @hide -->
+    <permission android:name="android.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO"
+                android:protectionLevel="signature|privileged|appop" />
+
     <!-- @SystemApi Allows requesting the framework broadcast the
          {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY} intent.
          @hide -->
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 8b6c901..27f8138 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -60,10 +60,11 @@
                     android:gravity="center"
                     android:textAppearance="@style/AutofillSaveUiTitle">
                 </TextView>
-                <LinearLayout
+                <FrameLayout
                     android:id="@+id/autofill_save_custom_subtitle"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
+                    android:minHeight="0dp"
                     android:visibility="gone"/>
 
             </LinearLayout>
diff --git a/core/res/res/layout/notification_expand_button.xml b/core/res/res/layout/notification_expand_button.xml
index 63fe471..2c6e0a7 100644
--- a/core/res/res/layout/notification_expand_button.xml
+++ b/core/res/res/layout/notification_expand_button.xml
@@ -52,7 +52,7 @@
             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:padding="@dimen/notification_expand_button_icon_padding"
             android:scaleType="fitCenter"
             android:importantForAccessibility="no"
             />
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index a49e547..6f879e4 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -674,7 +674,7 @@
     <string name="device_unlock_notification_name" msgid="2632928999862915709">"ডিভাইস আনলক করুন"</string>
     <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"অন্য কোনওভাবে আনলক করার চেষ্টা করুন"</string>
     <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"আপনার \'ফিঙ্গারপ্রিন্ট\' শনাক্ত করা না গেলে \'ফেস আনলক\' ব্যবহার করুন, যেমন যখন আপনার আঙুল ভিজে থাকে"</string>
-    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"আপনার মুখ শনাক্ত করা না গেলে \'ফিঙ্গারপ্রিন্ট আনলক\' ব্যবহার করুন, যেমন যখন পর্যাপ্ত আলো নেই"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"পর্যাপ্ত আলো না থাকার পরিস্থিতিতে, আপনার মুখ শনাক্ত করা না গেলে \'ফিঙ্গারপ্রিন্ট আনলক\' ব্যবহার করুন"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেস আনলক"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"\'ফেস আনলক\' ফিচার ব্যবহার করার ক্ষেত্রে হওয়া সমস্যা"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"আপনার ফেস মডেল মুছে দেওয়ার জন্য ট্যাপ করুন এবং তারপরে আবার ফেস যোগ করুন"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index a897170..2150324 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -476,7 +476,7 @@
     <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"atzitu kokapen-hornitzaileen komando gehigarriak"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Kokapen-hornitzailearen agindu gehigarriak erabiltzeko baimena ematen die aplikazioei. Horrela, agian aplikazioek GPSaren edo bestelako kokapenaren iturburuen funtzionamenduan eragina izan dezakete."</string>
     <string name="permlab_accessFineLocation" msgid="6426318438195622966">"lortu kokapen zehatza aurreko planoan bakarrik"</string>
-    <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Abian denean, aplikazioak kokapen zehatza lor dezake kokapen-zerbitzuen bidez. Aplikazioak kokapena lortu ahal izateko, kokapen-zerbitzuek aktibatuta egon behar dute gailuan. Bateria-erabilera areagotzen du horrek."</string>
+    <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Abian denean, aplikazioak kokapen zehatza lor dezake kokapen-zerbitzuen bidez. Aplikazioak kokapena lortu ahal izateko, kokapen-zerbitzuek aktibatuta egon behar dute gailuan. Agian bateria gehiago erabiliko du."</string>
     <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"atzitu gutxi gorabeherako kokapena aurreko planoan bakarrik"</string>
     <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Abian denean, aplikazioak gutxi gorabeherako kokapena lor dezake kokapen-zerbitzuen bidez. Aplikazioak kokapena lortu ahal izateko, kokapen-zerbitzuek aktibatuta egon behar dute gailuan."</string>
     <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"atzitu kokapena atzeko planoan"</string>
@@ -2137,7 +2137,7 @@
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Aplikazioak ez du grabatzeko baimenik, baina baliteke audioa grabatzea USB bidezko gailu horren bidez."</string>
     <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Pantaila nagusia"</string>
     <string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Atzera"</string>
-    <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Erabilitako azken aplikazioak"</string>
+    <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Azkenaldian erabilitako aplikazioak"</string>
     <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"Jakinarazpenak"</string>
     <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Ezarpen bizkorrak"</string>
     <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Piztu edo itzaltzeko leihoa"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 2867516..d7d29a4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -299,8 +299,8 @@
     <string name="android_system_label" msgid="5974767339591067210">"Système Android"</string>
     <string name="user_owner_label" msgid="8628726904184471211">"Passer au profil personnel"</string>
     <string name="managed_profile_label" msgid="7316778766973512382">"Passer au profil pro"</string>
-    <string name="user_owner_app_label" msgid="1553595155465750298">"Passer au <xliff:g id="APP_NAME">%1$s</xliff:g> personnel"</string>
-    <string name="managed_profile_app_label" msgid="367401088383965725">"Passer au <xliff:g id="APP_NAME">%1$s</xliff:g> professionnel"</string>
+    <string name="user_owner_app_label" msgid="1553595155465750298">"Passer à l\'application <xliff:g id="APP_NAME">%1$s</xliff:g> personnelle"</string>
+    <string name="managed_profile_app_label" msgid="367401088383965725">"Passer à l\'application <xliff:g id="APP_NAME">%1$s</xliff:g> professionnelle"</string>
     <string name="permgrouplab_contacts" msgid="4254143639307316920">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"accéder à vos contacts"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"Position"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5a98ef8..d2b6dc8 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -674,7 +674,7 @@
     <string name="device_unlock_notification_name" msgid="2632928999862915709">"기기 잠금 해제"</string>
     <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"다른 잠금 해제 방법 사용"</string>
     <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"손가락에 물기가 있는 등 지문이 인식되지 않을 때는 얼굴 인식 잠금 해제를 사용하세요."</string>
-    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"충분히 밝지 않은 경우 등 얼굴이 인식되지 않을 때는 지문 잠금 해제를 사용하세요."</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"주변이 어두운 경우 등 얼굴이 인식되지 않을 때는 지문 잠금 해제를 사용해 보세요."</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"얼굴 인식 잠금 해제"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"얼굴 인식 잠금 해제 문제"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"탭하여 얼굴 모델을 삭제한 후 다시 얼굴을 추가하세요"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 5f3b315..485e9b6 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -674,7 +674,7 @@
     <string name="device_unlock_notification_name" msgid="2632928999862915709">"डिव्हाइस अनलॉक"</string>
     <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"अनलॉक करण्याची दुसरी पद्धत वापरून पहा"</string>
     <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"तुमचे फिंगरप्रिंट ओळखले जात नाही, तेव्हा फेस अनलॉक वापरा, जसे की तुमची बोटे ओली असताना"</string>
-    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"तुमचा चेहरा ओळखला जात नाही, तेव्हा फिंगरप्रिंट अनलॉक वापरा, जसे की पुरेसा प्रकाश नसताना"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"पुरेसा प्रकाश नसणे इत्यादिमुळे तुमचा चेहरा ओळखला जात नाही, अशावेळी फिंगरप्रिंट अनलॉक वापरा"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फेस अनलॉक"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फेस अनलॉकसंबंधित समस्या"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"फेस मॉडेल हटवण्यासाठी टॅप करा, त्यानंतर तुमचा चेहरा पुन्हा जोडा"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 9583c0e5..628627d 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -675,7 +675,7 @@
     <string name="device_unlock_notification_name" msgid="2632928999862915709">"Desbloqueio do dispositivo"</string>
     <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Tente desbloquear de outra maneira"</string>
     <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Use o Desbloqueio facial quando sua impressão digital não for reconhecida, como quando seus dedos estiverem molhados"</string>
-    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Use o Desbloqueio por impressão digital quando seu rosto não for reconhecido, como quando não houver luz suficiente"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Use o Desbloqueio por impressão digital quando seu rosto não for reconhecido, se estiver escuro, por exemplo"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Toque para excluir seu modelo de rosto e crie um novo"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 9583c0e5..628627d 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -675,7 +675,7 @@
     <string name="device_unlock_notification_name" msgid="2632928999862915709">"Desbloqueio do dispositivo"</string>
     <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Tente desbloquear de outra maneira"</string>
     <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Use o Desbloqueio facial quando sua impressão digital não for reconhecida, como quando seus dedos estiverem molhados"</string>
-    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Use o Desbloqueio por impressão digital quando seu rosto não for reconhecido, como quando não houver luz suficiente"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Use o Desbloqueio por impressão digital quando seu rosto não for reconhecido, se estiver escuro, por exemplo"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Toque para excluir seu modelo de rosto e crie um novo"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 8573c20c..aa22aea 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -673,8 +673,8 @@
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"వేలిముద్ర చిహ్నం"</string>
     <string name="device_unlock_notification_name" msgid="2632928999862915709">"పరికర అన్‌లాక్"</string>
     <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"అన్‌లాక్ చేయడానికి మరొక మార్గాన్ని ట్రై చేయండి"</string>
-    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"మీ వేలిముద్ర గుర్తించబడనప్పుడు, మీ వేళ్లు తడిగా ఉన్నప్పుడు ఫేస్ అన్‌లాక్‌ను ఉపయోగించండి"</string>
-    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"మీ ఫేస్ గుర్తించబడనప్పుడు, తగినంత వెలుతురు లేనప్పుడు వేలిముద్ర అన్‌లాక్‌ను ఉపయోగించండి"</string>
+    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"మీ వేళ్లు తడిగా ఉండటం లేక ఇతరత్రా కారణాల వల్ల మీ వేలిముద్రను గుర్తించకపోతే, ఫేస్ అన్‌లాక్‌ను ఉపయోగించండి"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"తగినంత వెలుతురు లేకపోవడం లేక ఇతరత్రా కారణాల వల్ల మీ ఫేస్ గుర్తించబడనప్పుడు, వేలిముద్ర అన్‌లాక్‌ను ఉపయోగించండి"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ఫేస్ అన్‌లాక్"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ఫేస్ అన్‌లాక్‌తో సమస్య"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"ఫేస్ మోడల్‌ను తొలగించడానికి నొక్కండి, ఆపై మీ ముఖాన్ని మళ్లీ జోడించండి"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 936c978b..d34e976 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -675,8 +675,8 @@
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок відбитка пальця"</string>
     <string name="device_unlock_notification_name" msgid="2632928999862915709">"Розблокування пристрою"</string>
     <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Спробуйте інший спосіб розблокування"</string>
-    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Розблоковуйте пристрій за допомогою фейс-контролю, коли не вдається розпізнати ваш відбиток пальця (наприклад, коли у вас мокрі пальці)"</string>
-    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Розблоковуйте пристрій відбитком пальця, коли не вдається розпізнати ваше обличчя (наприклад, коли недостатньо світла)"</string>
+    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Якщо пристрій не розпізнає ваш відбиток пальця (наприклад, коли у вас мокрі руки), використовуйте фейс-контроль"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Якщо пристрій не розпізнає ваше обличчя (наприклад, коли освітлення погане), використовуйте відбиток пальця"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Фейс-контроль"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Сталася помилка з фейсконтролем"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Натисніть, щоб видалити свою модель обличчя, а потім знову додайте її"</string>
diff --git a/core/res/res/values-watch/dimens_material.xml b/core/res/res/values-watch/dimens_material.xml
index 2ab2d91..8becb08 100644
--- a/core/res/res/values-watch/dimens_material.xml
+++ b/core/res/res/values-watch/dimens_material.xml
@@ -47,11 +47,12 @@
     <dimen name="progress_bar_height">24dp</dimen>
 
     <!-- Progress bar message dimens -->
-    <dimen name="message_progress_dialog_text_size">18sp</dimen>
+    <dimen name="message_progress_dialog_text_size">14sp</dimen>
     <dimen name="message_progress_dialog_bottom_padding">80px</dimen>
     <dimen name="message_progress_dialog_top_padding">0dp</dimen>
     <dimen name="message_progress_dialog_start_padding">0dp</dimen>
     <dimen name="message_progress_dialog_end_padding">0dp</dimen>
+    <item name="message_progress_dialog_letter_spacing" format="float" type="dimen">0.021</item>
 
     <!-- fallback for screen percentage widths -->
     <dimen name="screen_percentage_05">0dp</dimen>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index 8698e86..f3e412d 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -100,7 +100,9 @@
 
     <style name="ProgressDialogMessage">
         <item name="android:textAlignment">center</item>
-        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="android:fontFamily">google-sans-text</item>
+        <item name="android:letterSpacing">@dimen/message_progress_dialog_letter_spacing</item>
+        <item name="textColor">?attr/textColorPrimary</item>
         <item name="textSize">@dimen/message_progress_dialog_text_size</item>
         <item name="paddingBottom">@dimen/message_progress_dialog_bottom_padding</item>
         <item name="paddingEnd">@dimen/message_progress_dialog_end_padding</item>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index ccdd945..06ec1dd 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1891,7 +1891,7 @@
     <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{1 小時}other{# 小時}}"</string>
     <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{1 小時}other{# 小時}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"直至<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_until" msgid="2250286190237669079">"完成時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+    <string name="zen_mode_until" msgid="2250286190237669079">"結束時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"直至<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (下一次響鬧)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"直至你關閉為止"</string>
     <string name="zen_mode_forever_dnd" msgid="3423201955704180067">"直至你關閉「請勿騷擾」功能"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3c296de..b211ac2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1026,6 +1026,12 @@
     <!-- Duration, in milliseconds, of the display white balance animated transitions. -->
     <integer name="config_displayWhiteBalanceTransitionTime">3000</integer>
 
+    <!-- Duration, in milliseconds, of the display white balance animated transitions when increasing cct. -->
+    <integer name="config_displayWhiteBalanceTransitionTimeIncrease">1000</integer>
+
+    <!-- Duration, in milliseconds, of the display white balance animated transitions when decreasing cct. -->
+    <integer name="config_displayWhiteBalanceTransitionTimeDecrease">40000</integer>
+
     <!-- Device states where the sensor based rotation values should be reversed around the Z axis
          for the default display.
          TODO(b/265312193): Remove this workaround when this bug is fixed.-->
@@ -1151,6 +1157,14 @@
     <!-- Allows activities to be launched on a long press on power during device setup. -->
     <bool name="config_allowStartActivityForLongPressOnPowerInSetup">false</bool>
 
+    <!-- Control the behavior when the user short presses the settings button.
+            0 - Nothing
+            1 - Launch notification panel
+         This needs to match the constants in
+         com/android/server/policy/PhoneWindowManager.java
+    -->
+    <integer name="config_shortPressOnSettingsBehavior">0</integer>
+
     <!-- Control the behavior when the user short presses the power button.
             0 - Nothing
             1 - Go to sleep (doze)
@@ -5394,6 +5408,7 @@
         <item>1,1,1.0,.4,1</item>
         <item>1,1,1.0,.15,15</item>
         <item>0,0,0.7,0,1</item>
+        <item>0,0,0.83333,0,1</item>
     </string-array>
 
     <!-- The integer index of the selected option in config_udfps_touch_detection_options -->
diff --git a/core/res/res/values/config_device_idle.xml b/core/res/res/values/config_device_idle.xml
index 98a5ff9..bc9ca3d 100644
--- a/core/res/res/values/config_device_idle.xml
+++ b/core/res/res/values/config_device_idle.xml
@@ -42,6 +42,15 @@
     <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FACTOR -->
     <item name="device_idle_light_idle_factor" format="float" type="integer">2.0</item>
 
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_INCREASE_LINEARLY -->
+    <bool name="device_idle_light_idle_increase_linearly">false</bool>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS -->
+    <integer name="device_idle_light_idle_linear_increase_factor_ms">300000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS -->
+    <integer name="device_idle_light_idle_flex_linear_increase_factor_ms">60000</integer>
+
     <!-- Default for DeviceIdleController.Constants.LIGHT_MAX_IDLE_TIMEOUT -->
     <integer name="device_idle_light_max_idle_to_ms">900000</integer>
 
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 71d696e..3ba150b 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -73,7 +73,7 @@
          CarrierConfigManager#KEY_AUTO_DATA_SWITCH_RAT_SIGNAL_SCORE_STRING_ARRAY.
          If 0, the device always switch to the higher score SIM.
          If < 0, the network type and signal strength based auto switch is disabled. -->
-    <integer name="auto_data_switch_score_tolerance">-1</integer>
+    <integer name="auto_data_switch_score_tolerance">4000</integer>
     <java-symbol type="integer" name="auto_data_switch_score_tolerance" />
 
     <!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec
@@ -219,4 +219,8 @@
     <bool name="telephony_analytics_switch">true</bool>
     <java-symbol type="bool" name="telephony_analytics_switch" />
 
+    <!-- Whether to enable modem on boot if behavior is not defined -->
+    <bool name="config_enable_cellular_on_boot_default">true</bool>
+    <java-symbol type="bool" name="config_enable_cellular_on_boot_default" />
+
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 49295fd..96c4bf4 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -349,6 +349,9 @@
     <!-- the height of the expand button pill -->
     <dimen name="notification_expand_button_pill_height">24dp</dimen>
 
+    <!-- the padding of the expand icon in the notification header -->
+    <dimen name="notification_expand_button_icon_padding">2dp</dimen>
+
     <!-- Vertical margin for the headerless notification content, when content has 1 line -->
     <!-- 16 * 2 (margins) + 24 (1 line) = 56 (notification) -->
     <dimen name="notification_headerless_margin_oneline">16dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 193f3ad..49a5a72 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1816,6 +1816,7 @@
   <java-symbol type="integer" name="config_lidNavigationAccessibility" />
   <java-symbol type="integer" name="config_lidOpenRotation" />
   <java-symbol type="integer" name="config_longPressOnHomeBehavior" />
+  <java-symbol type="integer" name="config_shortPressOnSettingsBehavior" />
   <java-symbol type="layout" name="global_actions" />
   <java-symbol type="layout" name="global_actions_item" />
   <java-symbol type="layout" name="global_actions_silent_mode" />
@@ -3485,6 +3486,8 @@
   <java-symbol type="array" name="config_displayWhiteBalanceDisplaySteps" />
   <java-symbol type="bool" name="config_displayWhiteBalanceLightModeAllowed" />
   <java-symbol type="integer" name="config_displayWhiteBalanceTransitionTime" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceTransitionTimeIncrease" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceTransitionTimeDecrease" />
 
   <!-- Device states where the sensor based rotation values should be reversed around the Z axis
        for the default display.
@@ -4537,7 +4540,10 @@
   <java-symbol type="integer" name="device_idle_light_idle_to_init_flex_ms" />
   <java-symbol type="integer" name="device_idle_light_idle_to_max_flex_ms" />
   <java-symbol type="integer" name="device_idle_light_idle_factor" />
+  <java-symbol type="bool" name="device_idle_light_idle_increase_linearly" />
   <java-symbol type="integer" name="device_idle_light_max_idle_to_ms" />
+  <java-symbol type="integer" name="device_idle_light_idle_linear_increase_factor_ms" />
+  <java-symbol type="integer" name="device_idle_light_idle_flex_linear_increase_factor_ms" />
   <java-symbol type="integer" name="device_idle_light_idle_maintenance_min_budget_ms" />
   <java-symbol type="integer" name="device_idle_light_idle_maintenance_max_budget_ms" />
   <java-symbol type="integer" name="device_idle_min_light_maintenance_time_ms" />
diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp
index 85d54e0..054d10c 100644
--- a/core/tests/BroadcastRadioTests/Android.bp
+++ b/core/tests/BroadcastRadioTests/Android.bp
@@ -38,7 +38,7 @@
     static_libs: [
         "services.core",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
         "testng",
         "mockito-target-extended",
     ],
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index a195228..75a7231 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -16,20 +16,20 @@
 
 package com.android.server.broadcastradio.aidl;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.after;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.app.compat.CompatChanges;
 import android.graphics.Bitmap;
@@ -81,8 +81,8 @@
 
     private static final int USER_ID_1 = 11;
     private static final int USER_ID_2 = 12;
-    private static final VerificationWithTimeout CALLBACK_TIMEOUT =
-            timeout(/* millis= */ 200);
+    private static final int CALLBACK_TIMEOUT_MS = 200;
+    private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(CALLBACK_TIMEOUT_MS);
     private static final int SIGNAL_QUALITY = 90;
     private static final long AM_FM_FREQUENCY_SPACING = 500;
     private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100};
@@ -166,12 +166,12 @@
 
     @Before
     public void setup() throws Exception {
-        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
         doReturn(true).when(() -> CompatChanges.isChangeEnabled(
                 eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt()));
+        doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier();
+        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
         doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser());
-        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
 
         mRadioModule = new RadioModule(mBroadcastRadioMock,
                 AidlTestUtils.makeDefaultModuleProperties());
@@ -222,7 +222,7 @@
             return Result.OK;
         }).when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean());
 
-        when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(null);
+        doReturn(null).when(mBroadcastRadioMock).getImage(anyInt());
 
         doAnswer(invocation -> {
             int configFlag = (int) invocation.getArguments()[0];
@@ -275,7 +275,7 @@
 
         mTunerSessions[0].setConfiguration(FM_BAND_CONFIG);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onConfigurationChanged(FM_BAND_CONFIG);
     }
 
@@ -446,26 +446,11 @@
 
         mTunerSessions[0].tune(initialSel);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(tuneInfo);
     }
 
     @Test
-    public void tune_forSystemUser() throws Exception {
-        when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM);
-        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
-        doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
-        ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        RadioManager.ProgramInfo tuneInfo =
-                AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY);
-        openAidlClients(/* numClients= */ 1);
-
-        mTunerSessions[0].tune(initialSel);
-
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
-    }
-
-    @Test
     public void tune_withUnknownErrorFromHal_fails() throws Exception {
         openAidlClients(/* numClients= */ 1);
         ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
@@ -525,7 +510,7 @@
 
         mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(any());
     }
 
@@ -604,7 +589,7 @@
 
         mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(seekUpInfo);
     }
 
@@ -625,8 +610,6 @@
     @Test
     public void cancel() throws Exception {
         openAidlClients(/* numClients= */ 1);
-        ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        mTunerSessions[0].tune(initialSel);
 
         mTunerSessions[0].cancel();
 
@@ -636,8 +619,6 @@
     @Test
     public void cancel_forNonCurrentUser_doesNotCancel() throws Exception {
         openAidlClients(/* numClients= */ 1);
-        ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        mTunerSessions[0].tune(initialSel);
         doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
 
         mTunerSessions[0].cancel();
@@ -686,8 +667,8 @@
     public void getImage_whenHalThrowsException_fails() throws Exception {
         openAidlClients(/* numClients= */ 1);
         String exceptionMessage = "HAL service died.";
-        when(mBroadcastRadioMock.getImage(anyInt()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock)
+                .getImage(anyInt());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].getImage(/* id= */ 1);
@@ -713,7 +694,8 @@
 
         mTunerSessions[0].startBackgroundScan();
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete();
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
+                .onBackgroundScanComplete();
     }
 
     @Test
@@ -905,7 +887,8 @@
         mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
                 /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
+                .onProgramListUpdated(any());
     }
 
     @Test
@@ -1160,8 +1143,8 @@
         Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1",
                 "mockParam2", "mockValue2");
         String exceptionMessage = "HAL service died.";
-        when(mBroadcastRadioMock.setParameters(any()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock)
+                .setParameters(any());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].setParameters(parametersSet);
@@ -1186,8 +1169,8 @@
         openAidlClients(/* numClients= */ 1);
         List<String> parameterKeys = List.of("mockKey1", "mockKey2");
         String exceptionMessage = "HAL service died.";
-        when(mBroadcastRadioMock.getParameters(any()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock)
+                .getParameters(any());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].getParameters(parameterKeys);
@@ -1198,7 +1181,7 @@
     }
 
     @Test
-    public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback()
+    public void onCurrentProgramInfoChanged_withNonCurrentUser_doesNotInvokeCallback()
             throws Exception {
         openAidlClients(1);
         doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser());
@@ -1206,7 +1189,7 @@
         mHalTunerCallback.onCurrentProgramInfoChanged(AidlTestUtils.makeHalProgramInfo(
                 AidlTestUtils.makeHalFmSelector(AM_FM_FREQUENCY_LIST[1]), SIGNAL_QUALITY));
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(any());
     }
 
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
index fac9eaa..6edfa02 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
@@ -16,22 +16,22 @@
 
 package com.android.server.broadcastradio.hal2;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.after;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.graphics.Bitmap;
 import android.hardware.broadcastradio.V2_0.Constants;
@@ -78,8 +78,8 @@
 
     private static final int USER_ID_1 = 11;
     private static final int USER_ID_2 = 12;
-    private static final VerificationWithTimeout CALLBACK_TIMEOUT =
-            timeout(/* millis= */ 200);
+    private static final int CALLBACK_TIMEOUT_MS = 200;
+    private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(CALLBACK_TIMEOUT_MS);
     private static final int SIGNAL_QUALITY = 1;
     private static final long AM_FM_FREQUENCY_SPACING = 500;
     private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100};
@@ -113,7 +113,7 @@
 
     @Before
     public void setup() throws Exception {
-        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
+        doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier();
         doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
         doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser());
@@ -170,7 +170,7 @@
             return Result.OK;
         }).when(mHalTunerSessionMock).scan(anyBoolean(), anyBoolean());
 
-        when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(new ArrayList<Byte>(0));
+        doReturn(new ArrayList<Byte>(0)).when(mBroadcastRadioMock).getImage(anyInt());
 
         doAnswer(invocation -> {
             int configFlag = (int) invocation.getArguments()[0];
@@ -227,7 +227,7 @@
 
         mTunerSessions[0].setConfiguration(FM_BAND_CONFIG);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onConfigurationChanged(FM_BAND_CONFIG);
     }
 
@@ -379,7 +379,7 @@
 
         mTunerSessions[0].tune(initialSel);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(tuneInfo);
     }
 
@@ -398,20 +398,6 @@
     }
 
     @Test
-    public void tune_forSystemUser() throws Exception {
-        when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM);
-        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
-        doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
-        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY);
-        openAidlClients(/* numClients= */ 1);
-
-        mTunerSessions[0].tune(initialSel);
-
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
-    }
-
-    @Test
     public void step_withDirectionUp() throws Exception {
         long initFreq = AM_FM_FREQUENCY_LIST[1];
         ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq);
@@ -455,7 +441,7 @@
 
         mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(any());
     }
 
@@ -533,7 +519,7 @@
 
         mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(seekUpInfo);
     }
 
@@ -554,8 +540,6 @@
     @Test
     public void cancel() throws Exception {
         openAidlClients(/* numClients= */ 1);
-        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        mTunerSessions[0].tune(initialSel);
 
         mTunerSessions[0].cancel();
 
@@ -563,22 +547,8 @@
     }
 
     @Test
-    public void cancel_forNonCurrentUser() throws Exception {
-        openAidlClients(/* numClients= */ 1);
-        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        mTunerSessions[0].tune(initialSel);
-        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
-
-        mTunerSessions[0].cancel();
-
-        verify(mHalTunerSessionMock, never()).cancel();
-    }
-
-    @Test
     public void cancel_forNonCurrentUser_doesNotCancel() throws Exception {
         openAidlClients(/* numClients= */ 1);
-        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
-        mTunerSessions[0].tune(initialSel);
         doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
 
         mTunerSessions[0].cancel();
@@ -627,8 +597,7 @@
     public void getImage_whenHalThrowsException_fails() throws Exception {
         openAidlClients(/* numClients= */ 1);
         String exceptionMessage = "HAL service died.";
-        when(mBroadcastRadioMock.getImage(anyInt()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock).getImage(anyInt());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].getImage(/* id= */ 1);
@@ -654,7 +623,8 @@
 
         mTunerSessions[0].startBackgroundScan();
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete();
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
+                .onBackgroundScanComplete();
     }
 
     @Test
@@ -845,8 +815,8 @@
         Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1",
                 "mockParam2", "mockValue2");
         String exceptionMessage = "HAL service died.";
-        when(mHalTunerSessionMock.setParameters(any()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock)
+                .setParameters(any());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].setParameters(parametersSet);
@@ -871,8 +841,8 @@
         openAidlClients(/* numClients= */ 1);
         List<String> parameterKeys = List.of("mockKey1", "mockKey2");
         String exceptionMessage = "HAL service died.";
-        when(mHalTunerSessionMock.getParameters(any()))
-                .thenThrow(new RemoteException(exceptionMessage));
+        doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock)
+                .getParameters(any());
 
         RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
             mTunerSessions[0].getParameters(parameterKeys);
@@ -883,7 +853,7 @@
     }
 
     @Test
-    public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback()
+    public void onCurrentProgramInfoChanged_withNonCurrentUser_doesNotInvokeCallback()
             throws Exception {
         openAidlClients(1);
         doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser());
@@ -891,7 +861,7 @@
         mHalTunerCallback.onCurrentProgramInfoChanged(TestUtils.makeHalProgramInfo(
                 TestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY));
 
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))
                 .onCurrentProgramInfoChanged(any());
     }
 
diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp
index 8c5d6d5..0e3bc65 100644
--- a/core/tests/GameManagerTests/Android.bp
+++ b/core/tests/GameManagerTests/Android.bp
@@ -30,7 +30,7 @@
         "frameworks-base-testutils",
         "junit",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
index 6f2366e..b631df1 100644
--- a/core/tests/PackageInstallerSessions/Android.bp
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -35,7 +35,7 @@
         "frameworks-base-testutils",
         "platform-test-annotations",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp
index 5260835..1fb5f2c 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp
@@ -18,7 +18,7 @@
         "platform-test-annotations",
         "platformprotosnano",
         "statsdprotolite",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: ["android.test.runner"],
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index 2b34ee2..7c1ac48 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -32,7 +32,7 @@
     static_libs: [
         "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: ["general-tests"],
     sdk_version: "test_current",
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 9cde296..2993a0e 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -44,24 +44,27 @@
         "frameworks-core-util-lib",
         "mockwebserver",
         "guava",
+        "android.view.accessibility.flags-aconfig-java",
         "androidx.core_core",
         "androidx.core_core-ktx",
         "androidx.test.espresso.core",
         "androidx.test.ext.junit",
         "androidx.test.runner",
         "androidx.test.rules",
+        "flag-junit",
         "junit-params",
         "kotlin-test",
         "mockito-target-minus-junit4",
         "androidx.test.uiautomator_uiautomator",
         "platform-test-annotations",
         "platform-compat-test-rules",
-        "truth-prebuilt",
+        "truth",
         "print-test-util-lib",
         "testng",
         "servicestests-utils",
         "device-time-shell-utils",
         "testables",
+        "com.android.text.flags-aconfig-java",
     ],
 
     libs: [
@@ -147,7 +150,7 @@
         "androidx.test.runner",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index a8a5059..3f78396 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -16,6 +16,8 @@
 
 package android.graphics;
 
+import static com.android.text.flags.Flags.FLAG_CUSTOM_LOCALE_FALLBACK;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -30,6 +32,9 @@
 import android.graphics.fonts.SystemFonts;
 import android.graphics.text.PositionedGlyphs;
 import android.graphics.text.TextRunShaper;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.text.FontConfig;
 import android.util.ArrayMap;
 
@@ -39,6 +44,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParserException;
@@ -107,6 +113,10 @@
         GLYPH_2EM_WIDTH = paint.measureText("a");
     }
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
     @Before
     public void setUp() {
         final AssetManager am =
@@ -877,6 +887,130 @@
         assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
     }
 
+    private static void assertA3emFontIsUsed(Typeface typeface) {
+        final Paint paint = new Paint();
+        assertNotNull(typeface);
+        paint.setTypeface(typeface);
+        assertTrue("a3em font must be used", GLYPH_3EM_WIDTH == paint.measureText("a")
+                && GLYPH_1EM_WIDTH == paint.measureText("b")
+                && GLYPH_1EM_WIDTH == paint.measureText("c"));
+    }
+
+    private static void assertB3emFontIsUsed(Typeface typeface) {
+        final Paint paint = new Paint();
+        assertNotNull(typeface);
+        paint.setTypeface(typeface);
+        assertTrue("b3em font must be used", GLYPH_1EM_WIDTH == paint.measureText("a")
+                && GLYPH_3EM_WIDTH == paint.measureText("b")
+                && GLYPH_1EM_WIDTH == paint.measureText("c"));
+    }
+
+    private static String getBaseXml(String font, String lang) {
+        final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<familyset>"
+                + "  <family>"
+                + "    <font weight='400' style='normal'>no_coverage.ttf</font>"
+                + "  </family>"
+                + "  <family name='named-family'>"
+                + "    <font weight='400' style='normal'>no_coverage.ttf</font>"
+                + "  </family>"
+                + "  <family lang='%s'>"
+                + "    <font weight='400' style='normal'>%s</font>"
+                + "  </family>"
+                + "</familyset>";
+        return String.format(xml, lang, font);
+    }
+
+    private static String getCustomizationXml(String font, String op, String lang) {
+        final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<fonts-modification version='1'>"
+                + "  <family customizationType='new-locale-family' operation='%s' lang='%s'>"
+                + "    <font weight='400' style='normal' fallbackFor='named-family'>%s</font>"
+                + "  </family>"
+                + "</fonts-modification>";
+        return String.format(xml, op, lang, font);
+    }
+
+    @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK)
+    @Test
+    public void testBuildSystemFallback__Customization_locale_prepend() {
+        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
+        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+
+        buildSystemFallback(
+                getBaseXml("a3em.ttf", "ja-JP"),
+                getCustomizationXml("b3em.ttf", "prepend", "ja-JP"),
+                fontMap, fallbackMap);
+        Typeface typeface = fontMap.get("named-family");
+
+        // operation "prepend" places font before the original font, thus b3em is used.
+        assertB3emFontIsUsed(typeface);
+    }
+
+    @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK)
+    @Test
+    public void testBuildSystemFallback__Customization_locale_replace() {
+        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
+        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+
+        buildSystemFallback(
+                getBaseXml("a3em.ttf", "ja-JP"),
+                getCustomizationXml("b3em.ttf", "replace", "ja-JP"),
+                fontMap, fallbackMap);
+        Typeface typeface = fontMap.get("named-family");
+
+        // operation "replace" removes the original font, thus b3em font is used.
+        assertB3emFontIsUsed(typeface);
+    }
+
+    @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK)
+    @Test
+    public void testBuildSystemFallback__Customization_locale_append() {
+        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
+        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+
+        buildSystemFallback(
+                getBaseXml("a3em.ttf", "ja-JP"),
+                getCustomizationXml("b3em.ttf", "append", "ja-JP"),
+                fontMap, fallbackMap);
+        Typeface typeface = fontMap.get("named-family");
+
+        // operation "append" comes next to the original font, so the original "a3em" is used.
+        assertA3emFontIsUsed(typeface);
+    }
+
+    @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK)
+    @Test
+    public void testBuildSystemFallback__Customization_locale_ScriptMismatch() {
+        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
+        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+
+        buildSystemFallback(
+                getBaseXml("a3em.ttf", "ja-JP"),
+                getCustomizationXml("b3em.ttf", "replace", "ko-KR"),
+                fontMap, fallbackMap);
+        Typeface typeface = fontMap.get("named-family");
+
+        // Since the script doesn't match, the customization is ignored.
+        assertA3emFontIsUsed(typeface);
+    }
+
+    @RequiresFlagsEnabled(FLAG_CUSTOM_LOCALE_FALLBACK)
+    @Test
+    public void testBuildSystemFallback__Customization_locale_SubscriptMatch() {
+        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
+        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+
+        buildSystemFallback(
+                getBaseXml("a3em.ttf", "ja-JP"),
+                getCustomizationXml("b3em.ttf", "replace", "ko-Hani-KR"),
+                fontMap, fallbackMap);
+        Typeface typeface = fontMap.get("named-family");
+
+        // Hani script is supported by Japanese, Jpan.
+        assertB3emFontIsUsed(typeface);
+    }
+
     @Test(expected = IllegalArgumentException.class)
     public void testBuildSystemFallback__Customization_new_named_family_no_name_exception() {
         final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>"
@@ -902,7 +1036,6 @@
         readFontCustomization(oemXml);
     }
 
-
     @Test
     public void testBuildSystemFallback_UpdatableFont() {
         final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
diff --git a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
index 55ded9c..517aeae 100644
--- a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
+++ b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
@@ -16,6 +16,10 @@
 
 package android.service.notification;
 
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
+
 import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM;
 
 import static junit.framework.Assert.assertEquals;
@@ -24,20 +28,40 @@
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.Mockito.spy;
+
+import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
 import android.os.Parcel;
+import android.os.SharedMemory;
+import android.testing.TestableContext;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Flag;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.FlagResolver;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @SmallTest
 @RunWith(Parameterized.class)
 public class NotificationRankingUpdateTest {
@@ -56,16 +80,368 @@
     @Parameterized.Parameter
     public boolean mRankingUpdateAshmem;
 
+    @Rule
+    public TestableContext mContext =
+            spy(new TestableContext(InstrumentationRegistry.getContext(), null));
+
+    protected TestableContext getContext() {
+        return mContext;
+    }
+
+    public static String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"};
+
+    /**
+     * Creates a NotificationRankingUpdate with prepopulated Ranking entries
+     * @param context A testable context, used for PendingIntent creation
+     * @return The NotificationRankingUpdate to be used as test data
+     */
+    public static NotificationRankingUpdate generateUpdate(TestableContext context) {
+        NotificationListenerService.Ranking[] rankings =
+                new NotificationListenerService.Ranking[mKeys.length];
+        for (int i = 0; i < mKeys.length; i++) {
+            final String key = mKeys[i];
+            NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
+            ranking.populate(
+                    key,
+                    i,
+                    !isIntercepted(i),
+                    getVisibilityOverride(i),
+                    getSuppressedVisualEffects(i),
+                    getImportance(i),
+                    getExplanation(key),
+                    getOverrideGroupKey(key),
+                    getChannel(key, i),
+                    getPeople(key, i),
+                    getSnoozeCriteria(key, i),
+                    getShowBadge(i),
+                    getUserSentiment(i),
+                    getHidden(i),
+                    lastAudiblyAlerted(i),
+                    getNoisy(i),
+                    getSmartActions(key, i, context),
+                    getSmartReplies(key, i),
+                    canBubble(i),
+                    isTextChanged(i),
+                    isConversation(i),
+                    getShortcutInfo(i),
+                    getRankingAdjustment(i),
+                    isBubble(i),
+                    getProposedImportance(i),
+                    hasSensitiveContent(i)
+            );
+            rankings[i] = ranking;
+        }
+        return new NotificationRankingUpdate(rankings);
+    }
+
+    /**
+     * Produces a visibility override value based on the provided index.
+     */
+    public static int getVisibilityOverride(int index) {
+        return index * 9;
+    }
+
+    /**
+     * Produces a group key based on the provided key.
+     */
+    public static String getOverrideGroupKey(String key) {
+        return key + key;
+    }
+
+    /**
+     * Produces a boolean that can be used to represent isIntercepted, based on the provided index.
+     */
+    public static boolean isIntercepted(int index) {
+        return index % 2 == 0;
+    }
+
+    /**
+     * Produces a suppressed visual effects value based on the provided index
+     */
+    public static int getSuppressedVisualEffects(int index) {
+        return index * 2;
+    }
+
+    /**
+     * Produces an importance value, based on the provided index
+     */
+    public static int getImportance(int index) {
+        return index;
+    }
+
+    /**
+     * Produces an explanation value, based on the provided key
+     */
+    public static String getExplanation(String key) {
+        return key + "explain";
+    }
+
+    /**
+     * Produces a notification channel, based on the provided key and index
+     */
+    public static NotificationChannel getChannel(String key, int index) {
+        return new NotificationChannel(key, key, getImportance(index));
+    }
+
+    /**
+     * Produces a boolean that can be used to represent showBadge, based on the provided index
+     */
+    public static boolean getShowBadge(int index) {
+        return index % 3 == 0;
+    }
+
+    /**
+     * Produces a user sentiment value, based on the provided index
+     */
+    public static int getUserSentiment(int index) {
+        switch(index % 3) {
+            case 0:
+                return USER_SENTIMENT_NEGATIVE;
+            case 1:
+                return USER_SENTIMENT_NEUTRAL;
+            case 2:
+                return USER_SENTIMENT_POSITIVE;
+        }
+        return USER_SENTIMENT_NEUTRAL;
+    }
+
+    /**
+     * Produces a boolean that can be used to represent "hidden," based on the provided index.
+     */
+    public static boolean getHidden(int index) {
+        return index % 2 == 0;
+    }
+
+    /**
+     * Produces a long to represent lastAudiblyAlerted based on the provided index.
+     */
+    public static long lastAudiblyAlerted(int index) {
+        return index * 2000L;
+    }
+
+    /**
+     * Produces a boolean that can be used to represent "noisy," based on the provided index.
+     */
+    public static boolean getNoisy(int index) {
+        return index < 1;
+    }
+
+    /**
+     * Produces strings that can be used to represent people, based on the provided key and index.
+     */
+    public static ArrayList<String> getPeople(String key, int index) {
+        ArrayList<String> people = new ArrayList<>();
+        for (int i = 0; i < index; i++) {
+            people.add(i + key);
+        }
+        return people;
+    }
+
+    /**
+     * Produces a number of snoozeCriteria, based on the provided key and index.
+     */
+    public static ArrayList<SnoozeCriterion> getSnoozeCriteria(String key, int index) {
+        ArrayList<SnoozeCriterion> snooze = new ArrayList<>();
+        for (int i = 0; i < index; i++) {
+            snooze.add(new SnoozeCriterion(key + i, getExplanation(key), key));
+        }
+        return snooze;
+    }
+
+    /**
+     * Produces a list of Actions which can be used to represent smartActions.
+     * These actions are built from pending intents with intent titles based on the provided
+     * key, and ids based on the provided index.
+     */
+    public static ArrayList<Notification.Action> getSmartActions(String key,
+                                                                 int index,
+                                                                 TestableContext context) {
+        ArrayList<Notification.Action> actions = new ArrayList<>();
+        for (int i = 0; i < index; i++) {
+            PendingIntent intent = PendingIntent.getBroadcast(
+                    context,
+                    index /*requestCode*/,
+                    new Intent("ACTION_" + key),
+                    PendingIntent.FLAG_IMMUTABLE /*flags*/);
+            actions.add(new Notification.Action.Builder(null /*icon*/, key, intent).build());
+        }
+        return actions;
+    }
+
+    /**
+     * Produces index number of "smart replies," all based on the provided key and index
+     */
+    public static ArrayList<CharSequence> getSmartReplies(String key, int index) {
+        ArrayList<CharSequence> choices = new ArrayList<>();
+        for (int i = 0; i < index; i++) {
+            choices.add("choice_" + key + "_" + i);
+        }
+        return choices;
+    }
+
+    /**
+     * Produces a boolean that can be  used to represent canBubble, based on the provided index
+     */
+    public static boolean canBubble(int index) {
+        return index % 4 == 0;
+    }
+
+    /**
+     * Produces a boolean that can be used to represent isTextChanged, based on the provided index.
+     */
+    public static boolean isTextChanged(int index) {
+        return index % 4 == 0;
+    }
+
+    /**
+     * Produces a boolean that can be used to represent isConversation, based on the provided index.
+     */
+    public static boolean isConversation(int index) {
+        return index % 4 == 0;
+    }
+
+    /**
+     * Produces a ShortcutInfo value based on the provided index.
+     */
+    public static ShortcutInfo getShortcutInfo(int index) {
+        ShortcutInfo si = new ShortcutInfo(
+                index, String.valueOf(index), "packageName", new ComponentName("1", "1"), null,
+                "title", 0, "titleResName", "text", 0, "textResName",
+                "disabledMessage", 0, "disabledMessageResName",
+                null, null, 0, null, 0, 0,
+                0, "iconResName", "bitmapPath", null, 0,
+                null, null, null, null);
+        return si;
+    }
+
+    /**
+     * Produces a rankingAdjustment value, based on the provided index.
+     */
+    public static int getRankingAdjustment(int index) {
+        return index % 3 - 1;
+    }
+
+    /**
+     * Produces a proposedImportance, based on the provided index.
+     */
+    public static int getProposedImportance(int index) {
+        return index % 5 - 1;
+    }
+
+    /**
+     * Produces a boolean that can be used to represent hasSensitiveContent, based on the provided
+     * index.
+     */
+    public static boolean hasSensitiveContent(int index) {
+        return index % 3 == 0;
+    }
+
+    /**
+     * Produces a boolean that can be used to represent isBubble, based on the provided index.
+     */
+    public static boolean isBubble(int index) {
+        return index % 4 == 0;
+    }
+
+    /**
+     * Checks that each of the pairs of actions in the two provided lists has identical titles,
+     * and that the lists have the same number of elements.
+     */
+    public void assertActionsEqual(
+            List<Notification.Action> expecteds, List<Notification.Action> actuals) {
+        Assert.assertEquals(expecteds.size(), actuals.size());
+        for (int i = 0; i < expecteds.size(); i++) {
+            Notification.Action expected = expecteds.get(i);
+            Notification.Action actual = actuals.get(i);
+            Assert.assertEquals(expected.title.toString(), actual.title.toString());
+        }
+    }
+
+    /**
+     * Checks that all subelements of the provided NotificationRankingUpdates are equal.
+     */
+    public void detailedAssertEquals(NotificationRankingUpdate a, NotificationRankingUpdate b) {
+        detailedAssertEquals(a.getRankingMap(), b.getRankingMap());
+    }
+
+    /**
+     * Checks that all subelements of the provided Ranking objects are equal.
+     */
+    public void detailedAssertEquals(String comment, NotificationListenerService.Ranking a,
+                                     NotificationListenerService.Ranking b) {
+        Assert.assertEquals(comment, a.getKey(), b.getKey());
+        Assert.assertEquals(comment, a.getRank(), b.getRank());
+        Assert.assertEquals(comment, a.matchesInterruptionFilter(), b.matchesInterruptionFilter());
+        Assert.assertEquals(comment, a.getLockscreenVisibilityOverride(),
+                b.getLockscreenVisibilityOverride());
+        Assert.assertEquals(comment, a.getSuppressedVisualEffects(),
+                b.getSuppressedVisualEffects());
+        Assert.assertEquals(comment, a.getImportance(), b.getImportance());
+        Assert.assertEquals(comment, a.getImportanceExplanation(), b.getImportanceExplanation());
+        Assert.assertEquals(comment, a.getOverrideGroupKey(), b.getOverrideGroupKey());
+        Assert.assertEquals(comment, a.getChannel().toString(), b.getChannel().toString());
+        Assert.assertEquals(comment, a.getAdditionalPeople(), b.getAdditionalPeople());
+        Assert.assertEquals(comment, a.getSnoozeCriteria(), b.getSnoozeCriteria());
+        Assert.assertEquals(comment, a.canShowBadge(), b.canShowBadge());
+        Assert.assertEquals(comment, a.getUserSentiment(), b.getUserSentiment());
+        Assert.assertEquals(comment, a.isSuspended(), b.isSuspended());
+        Assert.assertEquals(comment, a.getLastAudiblyAlertedMillis(),
+                b.getLastAudiblyAlertedMillis());
+        Assert.assertEquals(comment, a.isNoisy(), b.isNoisy());
+        Assert.assertEquals(comment, a.getSmartReplies(), b.getSmartReplies());
+        Assert.assertEquals(comment, a.canBubble(), b.canBubble());
+        Assert.assertEquals(comment, a.isConversation(), b.isConversation());
+        if (a.getConversationShortcutInfo() != null && b.getConversationShortcutInfo() != null) {
+            Assert.assertEquals(comment, a.getConversationShortcutInfo().getId(),
+                    b.getConversationShortcutInfo().getId());
+        } else {
+            // One or both must be null, so we can check for equality.
+            Assert.assertEquals(a.getConversationShortcutInfo(), b.getConversationShortcutInfo());
+        }
+        assertActionsEqual(a.getSmartActions(), b.getSmartActions());
+        Assert.assertEquals(a.getProposedImportance(), b.getProposedImportance());
+        Assert.assertEquals(a.hasSensitiveContent(), b.hasSensitiveContent());
+    }
+
+    /**
+     * Checks that the two RankingMaps have identical keys, and that each Ranking object for
+     * each of those keys is identical.
+     */
+    public void detailedAssertEquals(NotificationListenerService.RankingMap a,
+                                     NotificationListenerService.RankingMap b) {
+        NotificationListenerService.Ranking arank = new NotificationListenerService.Ranking();
+        NotificationListenerService.Ranking brank = new NotificationListenerService.Ranking();
+        assertArrayEquals(a.getOrderedKeys(), b.getOrderedKeys());
+        for (String key : a.getOrderedKeys()) {
+            a.getRanking(key, arank);
+            b.getRanking(key, brank);
+            detailedAssertEquals("ranking for key <" + key + ">", arank, brank);
+        }
+    }
+
     @Before
     public void setUp() {
         mNotificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "test channel",
                 NotificationManager.IMPORTANCE_DEFAULT);
 
-        SystemUiSystemPropertiesFlags.TEST_RESOLVER = flag -> {
-            if (flag.mSysPropKey.equals(RANKING_UPDATE_ASHMEM.mSysPropKey)) {
-                return mRankingUpdateAshmem;
+        SystemUiSystemPropertiesFlags.TEST_RESOLVER = new FlagResolver() {
+            @Override
+            public boolean isEnabled(Flag flag) {
+                if (flag.mSysPropKey.equals(RANKING_UPDATE_ASHMEM.mSysPropKey)) {
+                    return mRankingUpdateAshmem;
+                }
+                return new SystemUiSystemPropertiesFlags.DebugResolver().isEnabled(flag);
             }
-            return new SystemUiSystemPropertiesFlags.DebugResolver().isEnabled(flag);
+
+            @Override
+            public int getIntValue(Flag flag) {
+                return 0;
+            }
+
+            @Override
+            public String getStringValue(Flag flag) {
+                return null;
+            }
         };
     }
 
@@ -74,8 +450,13 @@
         SystemUiSystemPropertiesFlags.TEST_RESOLVER = null;
     }
 
-    public NotificationListenerService.Ranking createTestRanking(String key, int rank) {
+    /**
+     * Creates a mostly empty Test Ranking object with the specified key, rank, and smartActions.
+     */
+    public NotificationListenerService.Ranking createEmptyTestRanking(
+            String key, int rank, ArrayList<Notification.Action> actions) {
         NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
+
         ranking.populate(
                 /* key= */ key,
                 /* rank= */ rank,
@@ -93,7 +474,7 @@
                 /* hidden= */ false,
                 /* lastAudiblyAlertedMs= */ -1,
                 /* noisy= */ false,
-                /* smartActions= */ null,
+                /* smartActions= */ actions,
                 /* smartReplies= */ null,
                 /* canBubble= */ false,
                 /* isTextChanged= */ false,
@@ -107,54 +488,111 @@
         return ranking;
     }
 
+    // Tests parceling of NotificationRankingUpdate, and by extension, RankingMap and Ranking.
     @Test
-    public void testRankingUpdate_rankingConstructor() {
-        NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
-        NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
-                new NotificationListenerService.Ranking[]{ranking});
-
-        NotificationListenerService.RankingMap retrievedRankings = rankingUpdate.getRankingMap();
-        NotificationListenerService.Ranking retrievedRanking =
-                new NotificationListenerService.Ranking();
-        assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking));
-        assertEquals(123, retrievedRanking.getRank());
-    }
-
-    @Test
-    public void testRankingUpdate_parcelConstructor() {
-        NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
-        NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
-                new NotificationListenerService.Ranking[]{ranking});
-
-        Parcel parceledRankingUpdate = Parcel.obtain();
-        rankingUpdate.writeToParcel(parceledRankingUpdate, 0);
-        parceledRankingUpdate.setDataPosition(0);
-
-        NotificationRankingUpdate retrievedRankingUpdate = new NotificationRankingUpdate(
-                parceledRankingUpdate);
-
-        NotificationListenerService.RankingMap retrievedRankings =
-                retrievedRankingUpdate.getRankingMap();
-        assertNotNull(retrievedRankings);
+    public void testRankingUpdate_parcel() {
+        NotificationRankingUpdate nru = generateUpdate(getContext());
+        Parcel parcel = Parcel.obtain();
+        nru.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        NotificationRankingUpdate nru1 = NotificationRankingUpdate.CREATOR.createFromParcel(parcel);
         // The rankingUpdate file descriptor is only non-null in the new path.
         if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(
                 SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) {
-            assertTrue(retrievedRankingUpdate.isFdNotNullAndClosed());
+            assertTrue(nru1.isFdNotNullAndClosed());
         }
-        NotificationListenerService.Ranking retrievedRanking =
-                new NotificationListenerService.Ranking();
-        assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking));
-        assertEquals(123, retrievedRanking.getRank());
-        assertTrue(retrievedRankingUpdate.equals(rankingUpdate));
-        parceledRankingUpdate.recycle();
+        detailedAssertEquals(nru, nru1);
+        parcel.recycle();
+    }
+
+    // Tests parceling of RankingMap and RankingMap.equals
+    @Test
+    public void testRankingMap_parcel() {
+        NotificationListenerService.RankingMap rmap = generateUpdate(getContext()).getRankingMap();
+        Parcel parcel = Parcel.obtain();
+        rmap.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        NotificationListenerService.RankingMap rmap1 =
+                NotificationListenerService.RankingMap.CREATOR.createFromParcel(parcel);
+
+        detailedAssertEquals(rmap, rmap1);
+        Assert.assertEquals(rmap, rmap1);
+        parcel.recycle();
+    }
+
+    // Tests parceling of Ranking and Ranking.equals
+    @Test
+    public void testRanking_parcel() {
+        NotificationListenerService.Ranking ranking =
+                generateUpdate(getContext()).getRankingMap().getRawRankingObject(mKeys[0]);
+        Parcel parcel = Parcel.obtain();
+        ranking.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        NotificationListenerService.Ranking ranking1 =
+                new NotificationListenerService.Ranking(parcel);
+        detailedAssertEquals("rankings differ: ", ranking, ranking1);
+        Assert.assertEquals(ranking, ranking1);
+        parcel.recycle();
+    }
+
+    // Tests NotificationRankingUpdate.equals(), and by extension, RankingMap and Ranking.
+    @Test
+    public void testRankingUpdate_equals_legacy() {
+        NotificationRankingUpdate nru = generateUpdate(getContext());
+        NotificationRankingUpdate nru2 = generateUpdate(getContext());
+        detailedAssertEquals(nru, nru2);
+        Assert.assertEquals(nru, nru2);
+        NotificationListenerService.Ranking tweak =
+                nru2.getRankingMap().getRawRankingObject(mKeys[0]);
+        tweak.populate(
+                tweak.getKey(),
+                tweak.getRank(),
+                !tweak.matchesInterruptionFilter(), // note the inversion here!
+                tweak.getLockscreenVisibilityOverride(),
+                tweak.getSuppressedVisualEffects(),
+                tweak.getImportance(),
+                tweak.getImportanceExplanation(),
+                tweak.getOverrideGroupKey(),
+                tweak.getChannel(),
+                (ArrayList) tweak.getAdditionalPeople(),
+                (ArrayList) tweak.getSnoozeCriteria(),
+                tweak.canShowBadge(),
+                tweak.getUserSentiment(),
+                tweak.isSuspended(),
+                tweak.getLastAudiblyAlertedMillis(),
+                tweak.isNoisy(),
+                (ArrayList) tweak.getSmartActions(),
+                (ArrayList) tweak.getSmartReplies(),
+                tweak.canBubble(),
+                tweak.isTextChanged(),
+                tweak.isConversation(),
+                tweak.getConversationShortcutInfo(),
+                tweak.getRankingAdjustment(),
+                tweak.isBubble(),
+                tweak.getProposedImportance(),
+                tweak.hasSensitiveContent()
+        );
+        assertNotEquals(nru, nru2);
+    }
+
+    @Test
+    public void testRankingUpdate_rankingConstructor() {
+        NotificationRankingUpdate nru = generateUpdate(getContext());
+        NotificationRankingUpdate constructedNru = new NotificationRankingUpdate(
+                new NotificationListenerService.Ranking[]{
+                        nru.getRankingMap().getRawRankingObject(mKeys[0]),
+                        nru.getRankingMap().getRawRankingObject(mKeys[1]),
+                        nru.getRankingMap().getRawRankingObject(mKeys[2]),
+                        nru.getRankingMap().getRawRankingObject(mKeys[3]),
+                        nru.getRankingMap().getRawRankingObject(mKeys[4])
+                });
+
+        detailedAssertEquals(nru, constructedNru);
     }
 
     @Test
     public void testRankingUpdate_emptyParcelInCheck() {
-        NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
-        NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
-                new NotificationListenerService.Ranking[]{ranking});
-
+        NotificationRankingUpdate rankingUpdate = generateUpdate(getContext());
         Parcel parceledRankingUpdate = Parcel.obtain();
         rankingUpdate.writeToParcel(parceledRankingUpdate, 0);
 
@@ -163,37 +601,119 @@
         NotificationRankingUpdate retrievedRankingUpdate = new NotificationRankingUpdate(
                 parceledRankingUpdate);
         assertNull(retrievedRankingUpdate.getRankingMap());
+        parceledRankingUpdate.recycle();
     }
 
     @Test
     public void testRankingUpdate_describeContents() {
-        NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
-        NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
-                new NotificationListenerService.Ranking[]{ranking});
+        NotificationRankingUpdate rankingUpdate = generateUpdate(getContext());
         assertEquals(0, rankingUpdate.describeContents());
     }
 
     @Test
     public void testRankingUpdate_equals() {
-        NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
+        NotificationListenerService.Ranking ranking = createEmptyTestRanking(TEST_KEY, 123, null);
         NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
                 new NotificationListenerService.Ranking[]{ranking});
-        // Reflexive equality.
-        assertTrue(rankingUpdate.equals(rankingUpdate));
-        // Null or wrong class inequality.
+        // Reflexive equality, including handling nulls properly
+        detailedAssertEquals(rankingUpdate, rankingUpdate);
+        // Null or wrong class inequality
         assertFalse(rankingUpdate.equals(null));
         assertFalse(rankingUpdate.equals(ranking));
 
-        // Different ranking contents inequality.
-        NotificationListenerService.Ranking ranking2 = createTestRanking(TEST_KEY, 456);
+        // Different rank inequality
+        NotificationListenerService.Ranking ranking2 = createEmptyTestRanking(TEST_KEY, 456, null);
         NotificationRankingUpdate rankingUpdate2 = new NotificationRankingUpdate(
                 new NotificationListenerService.Ranking[]{ranking2});
         assertFalse(rankingUpdate.equals(rankingUpdate2));
 
-        // Same ranking contents equality.
-        ranking2 = createTestRanking(TEST_KEY, 123);
+        // Different key inequality
+        ranking2 = createEmptyTestRanking(TEST_KEY + "DIFFERENT", 123, null);
         rankingUpdate2 = new NotificationRankingUpdate(
                 new NotificationListenerService.Ranking[]{ranking2});
-        assertTrue(rankingUpdate.equals(rankingUpdate2));
+        assertFalse(rankingUpdate.equals(rankingUpdate2));
+    }
+
+    @Test
+    public void testRankingUpdate_writesSmartActionToParcel() {
+        if (!mRankingUpdateAshmem) {
+            return;
+        }
+        ArrayList<Notification.Action> actions = new ArrayList<>();
+        PendingIntent intent = PendingIntent.getBroadcast(
+                getContext(),
+                0 /*requestCode*/,
+                new Intent("ACTION_" + TEST_KEY),
+                PendingIntent.FLAG_IMMUTABLE /*flags*/);
+        actions.add(new Notification.Action.Builder(null /*icon*/, TEST_KEY, intent).build());
+
+        NotificationListenerService.Ranking ranking =
+                createEmptyTestRanking(TEST_KEY, 123, actions);
+        NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
+                new NotificationListenerService.Ranking[]{ranking});
+
+        Parcel parcel = Parcel.obtain();
+        rankingUpdate.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        SharedMemory fd = parcel.readParcelable(getClass().getClassLoader(), SharedMemory.class);
+        Bundle smartActionsBundle = parcel.readBundle(getClass().getClassLoader());
+
+        // Assert the file descriptor is valid
+        assertNotNull(fd);
+        assertFalse(fd.getFd() == -1);
+
+        // Assert that the smart action is in the parcel
+        assertNotNull(smartActionsBundle);
+        ArrayList<Notification.Action> recoveredActions =
+                smartActionsBundle.getParcelableArrayList(TEST_KEY, Notification.Action.class);
+        assertNotNull(recoveredActions);
+        assertEquals(actions.size(), recoveredActions.size());
+        assertEquals(actions.get(0).title.toString(), recoveredActions.get(0).title.toString());
+        parcel.recycle();
+    }
+
+    @Test
+    public void testRankingUpdate_handlesEmptySmartActionList() {
+        if (!mRankingUpdateAshmem) {
+            return;
+        }
+        ArrayList<Notification.Action> actions = new ArrayList<>();
+        NotificationListenerService.Ranking ranking =
+                createEmptyTestRanking(TEST_KEY, 123, actions);
+        NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
+                new NotificationListenerService.Ranking[]{ranking});
+
+        Parcel parcel = Parcel.obtain();
+        rankingUpdate.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        // Ensure that despite an empty actions list, we can still unparcel the update.
+        NotificationRankingUpdate newRankingUpdate = new NotificationRankingUpdate(parcel);
+        assertNotNull(newRankingUpdate);
+        assertNotNull(newRankingUpdate.getRankingMap());
+        detailedAssertEquals(rankingUpdate, newRankingUpdate);
+        parcel.recycle();
+    }
+
+    @Test
+    public void testRankingUpdate_handlesNullSmartActionList() {
+        if (!mRankingUpdateAshmem) {
+            return;
+        }
+        NotificationListenerService.Ranking ranking =
+                createEmptyTestRanking(TEST_KEY, 123, null);
+        NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
+                new NotificationListenerService.Ranking[]{ranking});
+
+        Parcel parcel = Parcel.obtain();
+        rankingUpdate.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        // Ensure that despite an empty actions list, we can still unparcel the update.
+        NotificationRankingUpdate newRankingUpdate = new NotificationRankingUpdate(parcel);
+        assertNotNull(newRankingUpdate);
+        assertNotNull(newRankingUpdate.getRankingMap());
+        detailedAssertEquals(rankingUpdate, newRankingUpdate);
+        parcel.recycle();
     }
 }
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 2afbb47..6a9fc04 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.view.accessibility.Flags.FLAG_FORCE_INVERT_COLOR;
 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
@@ -38,12 +39,18 @@
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Instrumentation;
+import android.app.UiModeManager;
 import android.content.Context;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Binder;
+import android.os.SystemProperties;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
+import android.util.Log;
 import android.view.WindowInsets.Side;
 import android.view.WindowInsets.Type;
 
@@ -52,9 +59,13 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -71,6 +82,10 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ViewRootImplTest {
+    private static final String TAG = "ViewRootImplTest";
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     private ViewRootImpl mViewRootImpl;
     private volatile boolean mKeyReceived = false;
@@ -101,6 +116,18 @@
                 mViewRootImpl = new ViewRootImpl(sContext, sContext.getDisplayNoVerify()));
     }
 
+    @After
+    public void teardown() {
+        ShellIdentityUtils.invokeWithShellPermissions(() -> {
+            Settings.Secure.resetToDefaults(sContext.getContentResolver(), TAG);
+
+            var uiModeManager = sContext.getSystemService(UiModeManager.class);
+            uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
+
+            setForceDarkSysProp(false);
+        });
+    }
+
     @Test
     public void adjustLayoutParamsForCompatibility_layoutFullscreen() {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
@@ -400,6 +427,100 @@
         assertThat(result).isFalse();
     }
 
+    @Test
+    public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
+        mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
+        ShellIdentityUtils.invokeWithShellPermissions(() -> {
+            Settings.Secure.putInt(
+                    sContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
+                    /* value= */ 0
+            );
+            var uiModeManager = sContext.getSystemService(UiModeManager.class);
+            uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
+        });
+
+        sInstrumentation.runOnMainSync(() ->
+                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
+        );
+
+        assertThat(mViewRootImpl.isForceDarkEnabled()).isFalse();
+    }
+
+    @Test
+    public void forceInvertOnDarkThemeOff_forceDarkModeEnabled() {
+        mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
+        ShellIdentityUtils.invokeWithShellPermissions(() -> {
+            Settings.Secure.putInt(
+                    sContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
+                    /* value= */ 1
+            );
+            var uiModeManager = sContext.getSystemService(UiModeManager.class);
+            uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
+        });
+
+        sInstrumentation.runOnMainSync(() ->
+                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
+        );
+
+        assertThat(mViewRootImpl.isForceDarkEnabled()).isTrue();
+    }
+
+    @Test
+    public void forceInvertOffForceDarkOff_forceDarkModeDisabled() {
+        mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
+        ShellIdentityUtils.invokeWithShellPermissions(() -> {
+            Settings.Secure.putInt(
+                    sContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
+                    /* value= */ 0
+            );
+
+            // TODO(b/297556388): figure out how to set this without getting blocked by SELinux
+            assumeTrue(setForceDarkSysProp(true));
+        });
+
+        sInstrumentation.runOnMainSync(() ->
+                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
+        );
+
+        assertThat(mViewRootImpl.isForceDarkEnabled()).isFalse();
+    }
+
+    @Test
+    public void forceInvertOffForceDarkOn_forceDarkModeEnabled() {
+        mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
+        ShellIdentityUtils.invokeWithShellPermissions(() -> {
+            Settings.Secure.putInt(
+                    sContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
+                    /* value= */ 0
+            );
+
+            assumeTrue(setForceDarkSysProp(true));
+        });
+
+        sInstrumentation.runOnMainSync(() ->
+                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
+        );
+
+        assertThat(mViewRootImpl.isForceDarkEnabled()).isTrue();
+    }
+
+    private boolean setForceDarkSysProp(boolean isForceDarkEnabled) {
+        try {
+            SystemProperties.set(
+                    ThreadedRenderer.DEBUG_FORCE_DARK,
+                    Boolean.toString(isForceDarkEnabled)
+            );
+            return true;
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to set force_dark sysprop", e);
+            return false;
+        }
+    }
+
     class KeyView extends View {
         KeyView(Context context) {
             super(context);
diff --git a/core/tests/coretests/src/android/widget/DifferentialMotionFlingHelperTest.java b/core/tests/coretests/src/android/widget/DifferentialMotionFlingHelperTest.java
index 51c8bc0..cce2faf 100644
--- a/core/tests/coretests/src/android/widget/DifferentialMotionFlingHelperTest.java
+++ b/core/tests/coretests/src/android/widget/DifferentialMotionFlingHelperTest.java
@@ -20,6 +20,8 @@
 import static org.junit.Assert.assertFalse;
 
 import android.view.MotionEvent;
+import android.widget.flags.FakeFeatureFlagsImpl;
+import android.widget.flags.Flags;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -54,6 +56,8 @@
     private final TestDifferentialMotionFlingTarget mFlingTarget =
             new TestDifferentialMotionFlingTarget();
 
+    private final FakeFeatureFlagsImpl mFakeWidgetFeatureFlags = new FakeFeatureFlagsImpl();
+
     private DifferentialMotionFlingHelper mFlingHelper;
 
     @Before
@@ -62,7 +66,10 @@
                 ApplicationProvider.getApplicationContext(),
                 mFlingTarget,
                 mVelocityThresholdCalculator,
-                mVelocityProvider);
+                mVelocityProvider,
+                mFakeWidgetFeatureFlags);
+        mFakeWidgetFeatureFlags.setFlag(
+                Flags.FLAG_ENABLE_PLATFORM_WIDGET_DIFFERENTIAL_MOTION_FLING, true);
     }
 
     @Test
@@ -139,6 +146,18 @@
     }
 
     @Test
+    public void flingFeatureFlagDisabled_noFlingCalculation() {
+        mFakeWidgetFeatureFlags.setFlag(
+                Flags.FLAG_ENABLE_PLATFORM_WIDGET_DIFFERENTIAL_MOTION_FLING, false);
+        mMinVelocity = 50;
+        mMaxVelocity = 100;
+        deliverEventWithVelocity(createPointerEvent(), MotionEvent.AXIS_VSCROLL, 60);
+
+        assertFalse(mVelocityCalculated);
+        assertEquals(0, mFlingTarget.mLastFlingVelocity, /* delta= */ 0);
+    }
+
+    @Test
     public void negativeFlingVelocityAboveMaximum_velocityClamped() {
         mMinVelocity = 50;
         mMaxVelocity = 100;
diff --git a/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java b/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java
new file mode 100644
index 0000000..263e563
--- /dev/null
+++ b/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2023 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.window;
+
+import static android.os.PerformanceHintManager.Session.CPU_LOAD_RESET;
+import static android.os.PerformanceHintManager.Session.CPU_LOAD_UP;
+import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT;
+import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
+import static android.view.SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN;
+import static android.view.SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_SELF;
+import static android.window.SystemPerformanceHinter.HINT_ADPF;
+import static android.window.SystemPerformanceHinter.HINT_ALL;
+import static android.window.SystemPerformanceHinter.HINT_SF_EARLY_WAKEUP;
+import static android.window.SystemPerformanceHinter.HINT_SF_FRAME_RATE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import android.os.PerformanceHintManager;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+
+/**
+ * Class for testing {@link android.window.SystemPerformanceHinter}.
+ *
+ * Build/Install/Run:
+ *  atest FrameworksCoreTests:android.window.SystemPerformanceHinterTests
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SystemPerformanceHinterTests {
+
+    private static final int DEFAULT_DISPLAY_ID = android.view.Display.DEFAULT_DISPLAY;
+    private static final int SECONDARY_DISPLAY_ID = DEFAULT_DISPLAY_ID + 1;
+    private static final int NO_ROOT_DISPLAY_ID = DEFAULT_DISPLAY_ID + 2;
+    private static final String TEST_REASON = "test";
+    private static final String TEST_OTHER_REASON = "test_other";
+
+    private SystemPerformanceHinter mHinter;
+    private SystemPerformanceHinterTests.RootProvider mRootProvider;
+
+    @Mock
+    private PerformanceHintManager.Session mAdpfSession;
+
+    @Mock
+    private SurfaceControl.Transaction mTransaction;
+    private SurfaceControl mDefaultDisplayRoot;
+    private SurfaceControl mSecondaryDisplayRoot;
+
+
+    @Before
+    public void setUpOnce() {
+        MockitoAnnotations.initMocks(this);
+
+        mDefaultDisplayRoot = new SurfaceControl();
+        mSecondaryDisplayRoot = new SurfaceControl();
+        mRootProvider = new SystemPerformanceHinterTests.RootProvider();
+        mRootProvider.put(DEFAULT_DISPLAY_ID, mDefaultDisplayRoot);
+        mRootProvider.put(SECONDARY_DISPLAY_ID, mSecondaryDisplayRoot);
+
+        mHinter = new SystemPerformanceHinter(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                mRootProvider,
+                () -> mTransaction);
+    }
+
+    @Test
+    public void testADPFHintWithoutADPFSession_expectThrows() {
+        assertThrows("Expected exception without ADPF session",
+                IllegalArgumentException.class, () -> {
+                    mHinter.startSession(HINT_ADPF, DEFAULT_DISPLAY_ID, TEST_REASON);
+                });
+    }
+
+    @Test
+    public void testSFVRRHintWithoutDisplayRootProvider_expectThrows() {
+        assertThrows("Expected exception without display root",
+                IllegalArgumentException.class, () -> {
+                    SystemPerformanceHinter hinter = new SystemPerformanceHinter(
+                            InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                            null /* displayRootProvider */,
+                            () -> mTransaction);
+                    hinter.startSession(HINT_SF_FRAME_RATE, DEFAULT_DISPLAY_ID, TEST_REASON);
+                });
+    }
+
+    @Test
+    public void testGetDefaultDisplayRoot() {
+        mHinter.startSession(HINT_SF_FRAME_RATE, DEFAULT_DISPLAY_ID, TEST_REASON);
+        assertEquals(DEFAULT_DISPLAY_ID, mRootProvider.lastRequestedDisplayId);
+        assertEquals(mDefaultDisplayRoot, mRootProvider.lastReturnedRoot);
+    }
+
+    @Test
+    public void testGetSecondaryDisplayRoot() {
+        mHinter.startSession(HINT_SF_FRAME_RATE, SECONDARY_DISPLAY_ID, TEST_REASON);
+        assertEquals(SECONDARY_DISPLAY_ID, mRootProvider.lastRequestedDisplayId);
+        assertEquals(mSecondaryDisplayRoot, mRootProvider.lastReturnedRoot);
+    }
+
+    @Test
+    public void testOnlyCacheDisplayRoots() {
+        mHinter.startSession(HINT_SF_FRAME_RATE, DEFAULT_DISPLAY_ID, TEST_REASON);
+        mHinter.startSession(HINT_SF_FRAME_RATE, DEFAULT_DISPLAY_ID, TEST_REASON);
+        mHinter.startSession(HINT_SF_FRAME_RATE, DEFAULT_DISPLAY_ID, TEST_REASON);
+        assertEquals(DEFAULT_DISPLAY_ID, mRootProvider.lastRequestedDisplayId);
+        assertEquals(mDefaultDisplayRoot, mRootProvider.lastReturnedRoot);
+    }
+
+    @Test
+    public void testVRRHint() {
+        final SystemPerformanceHinter.HighPerfSession session =
+                mHinter.startSession(HINT_SF_FRAME_RATE, DEFAULT_DISPLAY_ID, TEST_REASON);
+
+        // Expect it to get a display root
+        assertEquals(DEFAULT_DISPLAY_ID, mRootProvider.lastRequestedDisplayId);
+        assertEquals(mDefaultDisplayRoot, mRootProvider.lastReturnedRoot);
+
+        // Verify we call SF
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_HIGH));
+        verify(mTransaction).applyAsyncUnsafe();
+    }
+
+    @Test
+    public void testVRRHintCloseSession() {
+        final SystemPerformanceHinter.HighPerfSession session =
+                mHinter.startSession(HINT_SF_FRAME_RATE, DEFAULT_DISPLAY_ID, TEST_REASON);
+        reset(mTransaction);
+        session.close();
+
+        // Verify we call SF
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_SELF));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_DEFAULT));
+        verify(mTransaction).applyAsyncUnsafe();
+    }
+
+    @Test
+    public void testEarlyWakeupHint() {
+        final SystemPerformanceHinter.HighPerfSession session =
+                mHinter.startSession(HINT_SF_EARLY_WAKEUP, DEFAULT_DISPLAY_ID, TEST_REASON);
+
+        // Expect that this hint does not require a display root
+        assertEquals(0, mRootProvider.getCount);
+
+        // Verify we call SF
+        verify(mTransaction).setEarlyWakeupStart();
+        verify(mTransaction).applyAsyncUnsafe();
+    }
+
+    @Test
+    public void testEarlyWakeupHintCloseSession() {
+        final SystemPerformanceHinter.HighPerfSession session =
+                mHinter.startSession(HINT_SF_EARLY_WAKEUP, DEFAULT_DISPLAY_ID, TEST_REASON);
+        reset(mTransaction);
+        session.close();
+
+        // Verify we call SF
+        verify(mTransaction).setEarlyWakeupEnd();
+        verify(mTransaction).applyAsyncUnsafe();
+    }
+
+    @Test
+    public void testADPFHint() {
+        mHinter.setAdpfSession(mAdpfSession);
+        final SystemPerformanceHinter.HighPerfSession session =
+                mHinter.startSession(HINT_ADPF, DEFAULT_DISPLAY_ID, TEST_REASON);
+
+        // Expect that this hint does not require a display root
+        assertEquals(0, mRootProvider.getCount);
+
+        // Verify we call the perf manager
+        verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP));
+    }
+
+    @Test
+    public void testADPFHintCloseSession() {
+        mHinter.setAdpfSession(mAdpfSession);
+        final SystemPerformanceHinter.HighPerfSession session =
+                mHinter.startSession(HINT_ADPF, DEFAULT_DISPLAY_ID, TEST_REASON);
+        reset(mTransaction);
+        session.close();
+
+        // Verify we call the perf manager
+        verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
+    }
+
+    @Test
+    public void testAllHints() {
+        mHinter.setAdpfSession(mAdpfSession);
+        final SystemPerformanceHinter.HighPerfSession session =
+                mHinter.startSession(HINT_ALL, DEFAULT_DISPLAY_ID, TEST_REASON);
+
+        // Expect it to get a display root
+        assertEquals(DEFAULT_DISPLAY_ID, mRootProvider.lastRequestedDisplayId);
+        assertEquals(mDefaultDisplayRoot, mRootProvider.lastReturnedRoot);
+
+        // Verify we call SF and perf manager
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_HIGH));
+        verify(mTransaction).setEarlyWakeupStart();
+        verify(mTransaction).applyAsyncUnsafe();
+        verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP));
+    }
+
+    @Test
+    public void testAllHintsCloseSession() {
+        mHinter.setAdpfSession(mAdpfSession);
+        final SystemPerformanceHinter.HighPerfSession session =
+                mHinter.startSession(HINT_ALL, DEFAULT_DISPLAY_ID, TEST_REASON);
+        reset(mTransaction);
+        session.close();
+
+        // Verify we call SF and perf manager to clean up
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_SELF));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_DEFAULT));
+        verify(mTransaction).setEarlyWakeupEnd();
+        verify(mTransaction).applyAsyncUnsafe();
+        verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
+    }
+
+    @Test
+    public void testAutocloseable() {
+        mHinter.setAdpfSession(mAdpfSession);
+        try (final SystemPerformanceHinter.HighPerfSession session =
+                     mHinter.startSession(HINT_ALL, DEFAULT_DISPLAY_ID, TEST_REASON)) {
+            reset(mTransaction);
+            reset(mAdpfSession);
+        } finally {
+            // Verify we call SF and perf manager to clean up
+            verify(mTransaction).setFrameRateSelectionStrategy(
+                    eq(mDefaultDisplayRoot),
+                    eq(FRAME_RATE_SELECTION_STRATEGY_SELF));
+            verify(mTransaction).setFrameRateCategory(
+                    eq(mDefaultDisplayRoot),
+                    eq(FRAME_RATE_CATEGORY_DEFAULT));
+            verify(mTransaction).setEarlyWakeupEnd();
+            verify(mTransaction).applyAsyncUnsafe();
+            verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
+        }
+    }
+
+    @Test
+    public void testOverlappingHintsOnSameDisplay() {
+        mHinter.setAdpfSession(mAdpfSession);
+        final SystemPerformanceHinter.HighPerfSession session1 =
+                mHinter.startSession(HINT_ALL, DEFAULT_DISPLAY_ID, TEST_REASON);
+        // Verify we call SF and perf manager
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_HIGH));
+        verify(mTransaction).setEarlyWakeupStart();
+        verify(mTransaction).applyAsyncUnsafe();
+        verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP));
+        reset(mTransaction);
+        reset(mAdpfSession);
+
+        final SystemPerformanceHinter.HighPerfSession session2 =
+                mHinter.startSession(HINT_ALL, DEFAULT_DISPLAY_ID, TEST_OTHER_REASON);
+        // Verify we never call SF and perf manager since session1 is already running
+        verify(mTransaction, never()).setFrameRateSelectionStrategy(any(), anyInt());
+        verify(mTransaction, never()).setFrameRateCategory(any(), anyInt());
+        verify(mTransaction, never()).setEarlyWakeupEnd();
+        verify(mTransaction, never()).applyAsyncUnsafe();
+        verify(mAdpfSession, never()).sendHint(anyInt());
+
+        session2.close();
+        // Verify we have not cleaned up because session1 is still running
+        verify(mTransaction, never()).setFrameRateSelectionStrategy(any(), anyInt());
+        verify(mTransaction, never()).setFrameRateCategory(any(), anyInt());
+        verify(mTransaction, never()).setEarlyWakeupEnd();
+        verify(mTransaction, never()).applyAsyncUnsafe();
+        verify(mAdpfSession, never()).sendHint(anyInt());
+
+        session1.close();
+        // Verify we call SF and perf manager to clean up
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_SELF));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_DEFAULT));
+        verify(mTransaction).setEarlyWakeupEnd();
+        verify(mTransaction).applyAsyncUnsafe();
+        verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
+    }
+
+    @Test
+    public void testOverlappingHintsOnDifferentDisplays() {
+        mHinter.setAdpfSession(mAdpfSession);
+        final SystemPerformanceHinter.HighPerfSession session1 =
+                mHinter.startSession(HINT_ALL, DEFAULT_DISPLAY_ID, TEST_REASON);
+
+        // Verify we call SF and perf manager
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_HIGH));
+        verify(mTransaction).setEarlyWakeupStart();
+        verify(mTransaction).applyAsyncUnsafe();
+        verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP));
+        reset(mTransaction);
+        reset(mAdpfSession);
+
+        // Create a new session and ensure only per-display flags are updated and not global flags
+        final SystemPerformanceHinter.HighPerfSession session2 =
+                mHinter.startSession(HINT_ALL, SECONDARY_DISPLAY_ID, TEST_REASON);
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mSecondaryDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mSecondaryDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_HIGH));
+        verify(mTransaction, never()).setEarlyWakeupStart();
+        verify(mTransaction).applyAsyncUnsafe();
+        verify(mAdpfSession, never()).sendHint(anyInt());
+        reset(mTransaction);
+        reset(mAdpfSession);
+
+        // Close the primary display session and ensure it doesn't affect secondary display flags
+        // or any global flags still requested by the secondary display session
+        session1.close();
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_SELF));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_DEFAULT));
+        verify(mTransaction, never()).setFrameRateSelectionStrategy(
+                eq(mSecondaryDisplayRoot),
+                anyInt());
+        verify(mTransaction, never()).setFrameRateCategory(
+                eq(mSecondaryDisplayRoot),
+                anyInt());
+        verify(mTransaction, never()).setEarlyWakeupEnd();
+        verify(mTransaction).applyAsyncUnsafe();
+        verify(mAdpfSession, never()).sendHint(anyInt());
+        reset(mTransaction);
+        reset(mAdpfSession);
+
+        // Close all sessions, ensure it cleans up all the flags
+        session2.close();
+        verify(mTransaction, never()).setFrameRateSelectionStrategy(
+                eq(mDefaultDisplayRoot),
+                anyInt());
+        verify(mTransaction).setFrameRateSelectionStrategy(
+                eq(mSecondaryDisplayRoot),
+                eq(FRAME_RATE_SELECTION_STRATEGY_SELF));
+        verify(mTransaction).setFrameRateCategory(
+                eq(mSecondaryDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_DEFAULT));
+        verify(mTransaction).setEarlyWakeupEnd();
+        verify(mTransaction).applyAsyncUnsafe();
+        verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
+    }
+
+    private class RootProvider implements SystemPerformanceHinter.DisplayRootProvider {
+        private HashMap<Integer, SurfaceControl> mRoots = new HashMap<>();
+        public int getCount;
+        public int lastRequestedDisplayId = -1;
+        public SurfaceControl lastReturnedRoot;
+
+        void put(int displayId, SurfaceControl root) {
+            mRoots.put(displayId, root);
+        }
+
+        @NonNull
+        @Override
+        public SurfaceControl getRootForDisplay(int displayId) {
+            getCount++;
+            lastRequestedDisplayId = displayId;
+            lastReturnedRoot = mRoots.get(displayId);
+            return lastReturnedRoot;
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 681ba9c..06b62f8 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -29,6 +29,8 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.endsWith;
 import static org.mockito.ArgumentMatchers.any;
@@ -39,6 +41,8 @@
 import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.AlertDialog;
+import android.app.KeyguardManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -47,11 +51,17 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.Handler;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
+import android.view.View;
+import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.Flags;
 import android.view.accessibility.IAccessibilityManager;
 
 import androidx.lifecycle.Lifecycle;
@@ -90,6 +100,9 @@
     private TestAccessibilityShortcutChooserActivity mActivity;
 
     @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    @Rule
     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Mock
     private AccessibilityServiceInfo mAccessibilityServiceInfo;
@@ -101,6 +114,8 @@
     private ApplicationInfo mApplicationInfo;
     @Mock
     private IAccessibilityManager mAccessibilityManagerService;
+    @Mock
+    private KeyguardManager mKeyguardManager;
 
     @Before
     public void setUp() throws Exception {
@@ -116,22 +131,19 @@
                         Collections.singletonList(mAccessibilityServiceInfo)));
         when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
                 anyString(), anyInt(), anyInt())).thenReturn(true);
-        TestAccessibilityShortcutChooserActivity.setupForTesting(mAccessibilityManagerService);
-        mScenario = ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
-        mScenario.onActivity(activity -> mActivity = activity);
-        mScenario.moveToState(Lifecycle.State.CREATED);
-        mScenario.moveToState(Lifecycle.State.STARTED);
-        mScenario.moveToState(Lifecycle.State.RESUMED);
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
+        TestAccessibilityShortcutChooserActivity.setupForTesting(
+                mAccessibilityManagerService, mKeyguardManager);
     }
 
     @After
     public void cleanUp() {
-        mScenario.moveToState(Lifecycle.State.DESTROYED);
+        mScenario.close();
     }
 
     @Test
     public void doubleClickTestServiceAndClickDenyButton_permissionDialogDoesNotExist() {
+        launchActivity();
         openShortcutsList();
 
         // Performing the double-click is flaky so retry if needed.
@@ -154,6 +166,7 @@
             throws Exception {
         when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
                 eq(TEST_COMPONENT_NAME.getPackageName()), anyInt(), anyInt())).thenReturn(false);
+        launchActivity();
         openShortcutsList();
 
         onView(withText(TEST_LABEL)).perform(scrollTo(), click());
@@ -165,6 +178,7 @@
     @Test
     public void popEditShortcutMenuList_oneHandedModeEnabled_shouldBeInListView() {
         TestUtils.setOneHandedModeEnabled(this, /* enabled= */ true);
+        launchActivity();
         openShortcutsList();
 
         onView(allOf(withClassName(endsWith("ListView")), isDisplayed())).perform(swipeUp());
@@ -176,6 +190,7 @@
     @Test
     public void popEditShortcutMenuList_oneHandedModeDisabled_shouldNotBeInListView() {
         TestUtils.setOneHandedModeEnabled(this, /* enabled= */ false);
+        launchActivity();
         openShortcutsList();
 
         onView(allOf(withClassName(endsWith("ListView")), isDisplayed())).perform(swipeUp());
@@ -184,6 +199,30 @@
         onView(withText(ONE_HANDED_MODE)).inRoot(isDialog()).check(doesNotExist());
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ALLOW_SHORTCUT_CHOOSER_ON_LOCKSCREEN)
+    public void createDialog_onLockscreen_hasExpectedContent() {
+        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
+        launchActivity();
+
+        final AlertDialog dialog = mActivity.getMenuDialog();
+
+        assertThat(dialog.getButton(AlertDialog.BUTTON_POSITIVE).getVisibility())
+                .isEqualTo(View.GONE);
+        assertThat(dialog.getWindow().getAttributes().flags
+                & WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
+                .isEqualTo(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+    }
+
+    private void launchActivity() {
+        mScenario = ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
+        mScenario.onActivity(activity -> mActivity = activity);
+        mScenario.moveToState(Lifecycle.State.CREATED);
+        mScenario.moveToState(Lifecycle.State.STARTED);
+        mScenario.moveToState(Lifecycle.State.RESUMED);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
     private void openShortcutsList() {
         UiObject2 editButton = mDevice.findObject(By.text(EDIT_LABEL));
         if (editButton != null) {
@@ -198,9 +237,13 @@
     public static class TestAccessibilityShortcutChooserActivity extends
             AccessibilityShortcutChooserActivity {
         private static IAccessibilityManager sAccessibilityManagerService;
+        private static KeyguardManager sKeyguardManager;
 
-        public static void setupForTesting(IAccessibilityManager accessibilityManagerService) {
+        public static void setupForTesting(
+                IAccessibilityManager accessibilityManagerService,
+                KeyguardManager keyguardManager) {
             sAccessibilityManagerService = accessibilityManagerService;
+            sKeyguardManager = keyguardManager;
         }
 
         @Override
@@ -210,6 +253,9 @@
                 return new AccessibilityManager(this, new Handler(getMainLooper()),
                         sAccessibilityManagerService, /* userId= */ 0, /* serviceConnect= */ true);
             }
+            if (Context.KEYGUARD_SERVICE.equals(name)) {
+                return sKeyguardManager;
+            }
 
             return super.getSystemService(name);
         }
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index 3d04937..5f6eaf9 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/Android.bp
@@ -30,7 +30,7 @@
         "frameworks-base-testutils",
         "guava-android-testlib",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp
index fde7c08..2d778b1 100644
--- a/core/tests/mockingcoretests/Android.bp
+++ b/core/tests/mockingcoretests/Android.bp
@@ -38,7 +38,7 @@
         "androidx.test.ext.junit",
         "mockito-target-extended-minus-junit4",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
         "testables",
     ],
 
diff --git a/core/tests/nfctests/Android.bp b/core/tests/nfctests/Android.bp
index c74600b..f81be49 100644
--- a/core/tests/nfctests/Android.bp
+++ b/core/tests/nfctests/Android.bp
@@ -27,7 +27,7 @@
         "androidx.test.ext.junit",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.runner",
diff --git a/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp
index 063c569..931eac5 100644
--- a/core/tests/overlaytests/device_self_targeting/Android.bp
+++ b/core/tests/overlaytests/device_self_targeting/Android.bp
@@ -30,7 +30,7 @@
         "androidx.test.runner",
         "androidx.test.ext.junit",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
 
     optimize: {
diff --git a/core/tests/packagemonitortests/Android.bp b/core/tests/packagemonitortests/Android.bp
index 7b5d7df..b08850e 100644
--- a/core/tests/packagemonitortests/Android.bp
+++ b/core/tests/packagemonitortests/Android.bp
@@ -32,7 +32,7 @@
         "compatibility-device-util-axt",
         "frameworks-base-testutils",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/privacytests/Android.bp b/core/tests/privacytests/Android.bp
index bc3dd81..4e24cd5 100644
--- a/core/tests/privacytests/Android.bp
+++ b/core/tests/privacytests/Android.bp
@@ -14,7 +14,7 @@
         "junit",
         "rappor-tests",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp
index 3798da5..580e73c 100644
--- a/core/tests/utiltests/Android.bp
+++ b/core/tests/utiltests/Android.bp
@@ -33,7 +33,7 @@
         "frameworks-base-testutils",
         "mockito-target-minus-junit4",
         "androidx.test.ext.junit",
-        "truth-prebuilt",
+        "truth",
         "servicestests-utils",
     ],
 
diff --git a/core/tests/vibrator/Android.bp b/core/tests/vibrator/Android.bp
index 829409a..09608e9 100644
--- a/core/tests/vibrator/Android.bp
+++ b/core/tests/vibrator/Android.bp
@@ -18,7 +18,7 @@
         "androidx.test.runner",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
         "testng",
     ],
 
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index ad08026..c1d2235 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -41,7 +41,7 @@
     java_resource_dirs: ["tests/res"],
     java_resources: [":error_prone_android_framework_testdata"],
     static_libs: [
-        "truth-prebuilt",
+        "truth",
         "kxml2-2.3.0",
         "compile-testing-prebuilt",
         "error_prone_android_framework_lib",
diff --git a/framework-minus-apex-ravenwood-policies.txt b/framework-minus-apex-ravenwood-policies.txt
new file mode 100644
index 0000000..6bac58b
--- /dev/null
+++ b/framework-minus-apex-ravenwood-policies.txt
@@ -0,0 +1 @@
+# Ravenwood "policy" file for framework-minus-apex.
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index e7814cb..d1aceaf 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -114,6 +114,7 @@
             throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
         }
         throwIfCannotDraw(bitmap);
+        bitmap.setGainmap(null);
         mNativeCanvasWrapper = nInitRaster(bitmap.getNativeInstance());
         mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                 this, mNativeCanvasWrapper);
@@ -178,7 +179,7 @@
                 throw new IllegalStateException();
             }
             throwIfCannotDraw(bitmap);
-
+            bitmap.setGainmap(null);
             nSetBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance());
             mDensity = bitmap.mDensity;
         }
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 735bc18..52b0b95 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -236,7 +236,9 @@
             }
         }
 
-        return new FontConfig(families, filtered, resultNamedFamilies, lastModifiedDate,
+        return new FontConfig(families, filtered, resultNamedFamilies,
+                customization.getLocaleFamilyCustomizations(),
+                lastModifiedDate,
                 configVersion);
     }
 
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 9d32272..db1cc44 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -16,8 +16,11 @@
 
 package android.graphics;
 
+import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE;
+
 import android.annotation.ColorInt;
 import android.annotation.ColorLong;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -2125,7 +2128,7 @@
      * @return the font's recommended interline spacing.
      */
     public float getFontMetrics(FontMetrics metrics) {
-        return nGetFontMetrics(mNativePaint, metrics);
+        return nGetFontMetrics(mNativePaint, metrics, false);
     }
 
     /**
@@ -2139,6 +2142,32 @@
     }
 
     /**
+     * Get the font metrics used for the locale
+     *
+     * Obtain the metrics of the font that is used for the specified locale by
+     * {@link #setTextLocales(LocaleList)}. If multiple locales are specified, the minimum ascent
+     * and maximum descent will be set.
+     *
+     * This API is useful for determining the default line height of the empty text field, e.g.
+     * {@link android.widget.EditText}.
+     *
+     * Note, if the {@link android.graphics.Typeface} is created from the custom font files, its
+     * metrics are reserved, i.e. the ascent will be the custom font's ascent or smaller, the
+     * descent will be the custom font's descent or larger.
+     *
+     * Note, if the {@link android.graphics.Typeface} is a system fallback, e.g.
+     * {@link android.graphics.Typeface#SERIF}, the default font's metrics are reserved, i.e. the
+     * ascent will be the serif font's ascent or smaller, the descent will be the serif font's
+     * descent or larger.
+     *
+     * @param metrics an output parameter. All members will be set by calling this function.
+     */
+    @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+    public void getFontMetricsForLocale(@NonNull FontMetrics metrics) {
+        nGetFontMetrics(mNativePaint, metrics, true);
+    }
+
+    /**
      * Returns the font metrics value for the given text.
      *
      * If the text is rendered with multiple font files, this function returns the large ascent and
@@ -2318,7 +2347,7 @@
      * @return the font's interline spacing.
      */
     public int getFontMetricsInt(FontMetricsInt fmi) {
-        return nGetFontMetricsInt(mNativePaint, fmi);
+        return nGetFontMetricsInt(mNativePaint, fmi, false);
     }
 
     public FontMetricsInt getFontMetricsInt() {
@@ -2328,6 +2357,32 @@
     }
 
     /**
+     * Get the font metrics used for the locale
+     *
+     * Obtain the metrics of the font that is used for the specified locale by
+     * {@link #setTextLocales(LocaleList)}. If multiple locales are specified, the minimum ascent
+     * and maximum descent will be set.
+     *
+     * This API is useful for determining the default line height of the empty text field, e.g.
+     * {@link android.widget.EditText}.
+     *
+     * Note, if the {@link android.graphics.Typeface} is created from the custom font files, its
+     * metrics are reserved, i.e. the ascent will be the custom font's ascent or smaller, the
+     * descent will be the custom font's descent or larger.
+     *
+     * Note, if the {@link android.graphics.Typeface} is a system fallback, e.g.
+     * {@link android.graphics.Typeface#SERIF}, the default font's metrics are reserved, i.e. the
+     * ascent will be the serif font's ascent or smaller, the descent will be the serif font's
+     * descent or larger.
+     *
+     * @param metrics an output parameter. All members will be set by calling this function.
+     */
+    @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+    public void getFontMetricsIntForLocale(@NonNull FontMetricsInt metrics) {
+        nGetFontMetricsInt(mNativePaint, metrics, true);
+    }
+
+    /**
      * Return the recommend line spacing based on the current typeface and
      * text size.
      *
@@ -3446,9 +3501,11 @@
     @FastNative
     private static native void nSetFontFeatureSettings(long paintPtr, String settings);
     @FastNative
-    private static native float nGetFontMetrics(long paintPtr, FontMetrics metrics);
+    private static native float nGetFontMetrics(long paintPtr, FontMetrics metrics,
+            boolean useLocale);
     @FastNative
-    private static native int nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi);
+    private static native int nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi,
+            boolean useLocale);
 
     // ---------------- @CriticalNative ------------------------
 
diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
index b458dd9..6e04a2f 100644
--- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java
+++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.FontListParser;
+import android.text.FontConfig;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -34,6 +35,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 /**
@@ -52,14 +54,19 @@
 
         private final List<Alias> mAdditionalAliases;
 
+        private final List<FontConfig.Customization.LocaleFallback> mLocaleFamilyCustomizations;
+
         public Result() {
             mAdditionalNamedFamilies = Collections.emptyMap();
+            mLocaleFamilyCustomizations = Collections.emptyList();
             mAdditionalAliases = Collections.emptyList();
         }
 
         public Result(Map<String, NamedFamilyList> additionalNamedFamilies,
+                List<FontConfig.Customization.LocaleFallback> localeFamilyCustomizations,
                 List<Alias> additionalAliases) {
             mAdditionalNamedFamilies = additionalNamedFamilies;
+            mLocaleFamilyCustomizations = localeFamilyCustomizations;
             mAdditionalAliases = additionalAliases;
         }
 
@@ -70,6 +77,10 @@
         public List<Alias> getAdditionalAliases() {
             return mAdditionalAliases;
         }
+
+        public List<FontConfig.Customization.LocaleFallback> getLocaleFamilyCustomizations() {
+            return mLocaleFamilyCustomizations;
+        }
     }
 
     /**
@@ -89,7 +100,9 @@
     }
 
     private static Result validateAndTransformToResult(
-            List<NamedFamilyList> families, List<Alias> aliases) {
+            List<NamedFamilyList> families,
+            List<FontConfig.Customization.LocaleFallback> outLocaleFamilies,
+            List<Alias> aliases) {
         HashMap<String, NamedFamilyList> namedFamily = new HashMap<>();
         for (int i = 0; i < families.size(); ++i) {
             final NamedFamilyList family = families.get(i);
@@ -105,7 +118,7 @@
                                 + "requires fallackTarget attribute");
             }
         }
-        return new Result(namedFamily, aliases);
+        return new Result(namedFamily, outLocaleFamilies, aliases);
     }
 
     private static Result readFamilies(
@@ -115,12 +128,13 @@
     ) throws XmlPullParserException, IOException {
         List<NamedFamilyList> families = new ArrayList<>();
         List<Alias> aliases = new ArrayList<>();
+        List<FontConfig.Customization.LocaleFallback> outLocaleFamilies = new ArrayList<>();
         parser.require(XmlPullParser.START_TAG, null, "fonts-modification");
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("family")) {
-                readFamily(parser, fontDir, families, updatableFontMap);
+                readFamily(parser, fontDir, families, outLocaleFamilies, updatableFontMap);
             } else if (tag.equals("family-list")) {
                 readFamilyList(parser, fontDir, families, updatableFontMap);
             } else if (tag.equals("alias")) {
@@ -129,13 +143,14 @@
                 FontListParser.skip(parser);
             }
         }
-        return validateAndTransformToResult(families, aliases);
+        return validateAndTransformToResult(families, outLocaleFamilies, aliases);
     }
 
     private static void readFamily(
             @NonNull XmlPullParser parser,
             @NonNull String fontDir,
             @NonNull List<NamedFamilyList> out,
+            @NonNull List<FontConfig.Customization.LocaleFallback> outCustomization,
             @Nullable Map<String, File> updatableFontMap)
             throws XmlPullParserException, IOException {
         final String customizationType = parser.getAttributeValue(null, "customizationType");
@@ -148,6 +163,29 @@
             if (fontFamily != null) {
                 out.add(fontFamily);
             }
+        } else if (customizationType.equals("new-locale-family")) {
+            final String lang = parser.getAttributeValue(null, "lang");
+            final String op = parser.getAttributeValue(null, "operation");
+            final int intOp;
+            if (op.equals("append")) {
+                intOp = FontConfig.Customization.LocaleFallback.OPERATION_APPEND;
+            } else if (op.equals("prepend")) {
+                intOp = FontConfig.Customization.LocaleFallback.OPERATION_PREPEND;
+            } else if (op.equals("replace")) {
+                intOp = FontConfig.Customization.LocaleFallback.OPERATION_REPLACE;
+            } else {
+                throw new IllegalArgumentException("Unknown operation=" + op);
+            }
+
+            final FontConfig.FontFamily family = FontListParser.readFamily(
+                    parser, fontDir, updatableFontMap, false);
+
+            // For ignoring the customization, consume the new-locale-family element but don't
+            // register any customizations.
+            if (com.android.text.flags.Flags.customLocaleFallback()) {
+                outCustomization.add(new FontConfig.Customization.LocaleFallback(
+                        Locale.forLanguageTag(lang), intOp, family));
+            }
         } else {
             throw new IllegalArgumentException("Unknown customizationType=" + customizationType);
         }
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index d4e35b3..618aa5b 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -16,10 +16,15 @@
 
 package android.graphics.fonts;
 
+import static android.text.FontConfig.Customization.LocaleFallback.OPERATION_APPEND;
+import static android.text.FontConfig.Customization.LocaleFallback.OPERATION_PREPEND;
+import static android.text.FontConfig.Customization.LocaleFallback.OPERATION_REPLACE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.FontListParser;
 import android.graphics.Typeface;
+import android.os.LocaleList;
 import android.text.FontConfig;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -38,6 +43,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -119,7 +125,6 @@
             }
         }
 
-
         final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
                 defaultFonts, languageTags, variant, xmlFamily.getVariableFontFamilyType(), false,
                 cache);
@@ -300,11 +305,11 @@
         } catch (IOException e) {
             Log.e(TAG, "Failed to open/read system font configurations.", e);
             return new FontConfig(Collections.emptyList(), Collections.emptyList(),
-                    Collections.emptyList(), 0, 0);
+                    Collections.emptyList(), Collections.emptyList(), 0, 0);
         } catch (XmlPullParserException e) {
             Log.e(TAG, "Failed to parse the system font configuration.", e);
             return new FontConfig(Collections.emptyList(), Collections.emptyList(),
-                    Collections.emptyList(), 0, 0);
+                    Collections.emptyList(), Collections.emptyList(), 0, 0);
         }
     }
 
@@ -328,6 +333,8 @@
             ArrayMap<String, ByteBuffer> outBufferCache) {
 
         final ArrayMap<String, NativeFamilyListSet> fallbackListMap = new ArrayMap<>();
+        final List<FontConfig.Customization.LocaleFallback> localeFallbacks =
+                fontConfig.getLocaleFallbackCustomizations();
 
         final List<FontConfig.NamedFamilyList> namedFamilies = fontConfig.getNamedFamilyLists();
         for (int i = 0; i < namedFamilies.size(); ++i) {
@@ -336,10 +343,54 @@
         }
 
         // Then, add fallback fonts to the fallback map.
+        final List<FontConfig.Customization.LocaleFallback> customizations = new ArrayList<>();
         final List<FontConfig.FontFamily> xmlFamilies = fontConfig.getFontFamilies();
+        final SparseIntArray seenCustomization = new SparseIntArray();
         for (int i = 0; i < xmlFamilies.size(); i++) {
             final FontConfig.FontFamily xmlFamily = xmlFamilies.get(i);
-            pushFamilyToFallback(xmlFamily, fallbackListMap, outBufferCache);
+
+            customizations.clear();
+            for (int j = 0; j < localeFallbacks.size(); ++j) {
+                if (seenCustomization.get(j, -1) != -1) {
+                    continue;  // The customization is already applied.
+                }
+                FontConfig.Customization.LocaleFallback localeFallback = localeFallbacks.get(j);
+                if (scriptMatch(xmlFamily.getLocaleList(), localeFallback.getScript())) {
+                    customizations.add(localeFallback);
+                    seenCustomization.put(j, 1);
+                }
+            }
+
+            if (customizations.isEmpty()) {
+                pushFamilyToFallback(xmlFamily, fallbackListMap, outBufferCache);
+            } else {
+                for (int j = 0; j < customizations.size(); ++j) {
+                    FontConfig.Customization.LocaleFallback localeFallback = customizations.get(j);
+                    if (localeFallback.getOperation() == OPERATION_PREPEND) {
+                        pushFamilyToFallback(localeFallback.getFamily(), fallbackListMap,
+                                outBufferCache);
+                    }
+                }
+                boolean isReplaced = false;
+                for (int j = 0; j < customizations.size(); ++j) {
+                    FontConfig.Customization.LocaleFallback localeFallback = customizations.get(j);
+                    if (localeFallback.getOperation() == OPERATION_REPLACE) {
+                        pushFamilyToFallback(localeFallback.getFamily(), fallbackListMap,
+                                outBufferCache);
+                        isReplaced = true;
+                    }
+                }
+                if (!isReplaced) {  // If nothing is replaced, push the original one.
+                    pushFamilyToFallback(xmlFamily, fallbackListMap, outBufferCache);
+                }
+                for (int j = 0; j < customizations.size(); ++j) {
+                    FontConfig.Customization.LocaleFallback localeFallback = customizations.get(j);
+                    if (localeFallback.getOperation() == OPERATION_APPEND) {
+                        pushFamilyToFallback(localeFallback.getFamily(), fallbackListMap,
+                                outBufferCache);
+                    }
+                }
+            }
         }
 
         // Build the font map and fallback map.
@@ -365,4 +416,42 @@
         Typeface.initSystemDefaultTypefaces(fallbackMap, fontConfig.getAliases(), result);
         return result;
     }
+
+    private static boolean scriptMatch(LocaleList localeList, String targetScript) {
+        if (localeList == null || localeList.isEmpty()) {
+            return false;
+        }
+        for (int i = 0; i < localeList.size(); ++i) {
+            Locale locale = localeList.get(i);
+            if (locale == null) {
+                continue;
+            }
+            String baseScript = FontConfig.resolveScript(locale);
+            if (baseScript.equals(targetScript)) {
+                return true;
+            }
+
+            // Subtag match
+            if (targetScript.equals("Bopo") && baseScript.equals("Hanb")) {
+                // Hanb is Han with Bopomofo.
+                return true;
+            } else if (targetScript.equals("Hani")) {
+                if (baseScript.equals("Hanb") || baseScript.equals("Hans")
+                        || baseScript.equals("Hant") || baseScript.equals("Kore")
+                        || baseScript.equals("Jpan")) {
+                    // Han id suppoted by Taiwanese, Traditional Chinese, Simplified Chinese, Korean
+                    // and Japanese.
+                    return true;
+                }
+            } else if (targetScript.equals("Hira") || targetScript.equals("Hrkt")
+                    || targetScript.equals("Kana")) {
+                if (baseScript.equals("Jpan") || baseScript.equals("Hrkt")) {
+                    // Hiragana, Hiragana-Katakana, Katakana is supported by Japanese and
+                    // Hiragana-Katakana script.
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index e81525f..f5e5803 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -134,10 +134,25 @@
      */
     public static final int LINE_BREAK_STYLE_STRICT = 3;
 
+    /**
+     * The line break style that used for preventing automatic line breaking.
+     *
+     * This is useful when you want to preserve some words in the same line by using
+     * {@link android.text.style.LineBreakConfigSpan} or
+     * {@link android.text.style.LineBreakConfigSpan.NoBreakSpan} as a shorthand.
+     * Note that even if this style is specified, the grapheme based line break is still performed
+     * for preventing clipping text.
+     *
+     * @see android.text.style.LineBreakConfigSpan
+     * @see android.text.style.LineBreakConfigSpan.NoBreakSpan
+     */
+    @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
+    public static final int LINE_BREAK_STYLE_NO_BREAK = 4;
+
     /** @hide */
     @IntDef(prefix = { "LINE_BREAK_STYLE_" }, value = {
             LINE_BREAK_STYLE_NONE, LINE_BREAK_STYLE_LOOSE, LINE_BREAK_STYLE_NORMAL,
-            LINE_BREAK_STYLE_STRICT, LINE_BREAK_STYLE_UNSPECIFIED
+            LINE_BREAK_STYLE_STRICT, LINE_BREAK_STYLE_UNSPECIFIED, LINE_BREAK_STYLE_NO_BREAK
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface LineBreakStyle {}
diff --git a/keystore/aaid/aidl/Android.bp b/keystore/aaid/aidl/Android.bp
new file mode 100644
index 0000000..97acfb4
--- /dev/null
+++ b/keystore/aaid/aidl/Android.bp
@@ -0,0 +1,31 @@
+// Copyright 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.security.aaid_aidl",
+    srcs: ["android/security/keystore/*.aidl"],
+    unstable: true,
+    backend: {
+        rust: {
+            enabled: true,
+        },
+        cpp: {
+            enabled: true,
+        },
+    },
+}
diff --git a/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl b/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
new file mode 100644
index 0000000..c360cb8
--- /dev/null
+++ b/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2023, 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.keystore;
+
+import android.security.keystore.KeyAttestationApplicationId;
+
+/** @hide */
+interface IKeyAttestationApplicationIdProvider {
+    /**
+     * Provides information describing the possible applications identified by a UID.
+     * @hide
+     */
+    KeyAttestationApplicationId getKeyAttestationApplicationId(int uid);
+}
diff --git a/keystore/aaid/aidl/android/security/keystore/KeyAttestationApplicationId.aidl b/keystore/aaid/aidl/android/security/keystore/KeyAttestationApplicationId.aidl
new file mode 100644
index 0000000..c33e830
--- /dev/null
+++ b/keystore/aaid/aidl/android/security/keystore/KeyAttestationApplicationId.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023, 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.keystore;
+
+import android.security.keystore.KeyAttestationPackageInfo;
+
+/**
+ * @hide
+ * The information aggregated by this parcelable is used by keystore to identify a caller of the
+ * keystore API toward a remote party. It aggregates multiple PackageInfos because keystore
+ * can only determine a caller by uid granularity, and a uid can be shared by multiple packages.
+ * The remote party must decide if it trusts all of the packages enough to consider the
+ * confidentiality of the key material in question intact.
+ */
+parcelable KeyAttestationApplicationId {
+    KeyAttestationPackageInfo[] packageInfos;
+}
diff --git a/keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl b/keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl
new file mode 100644
index 0000000..5f647d0
--- /dev/null
+++ b/keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023, 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.keystore;
+
+import android.security.keystore.Signature;
+
+/**
+ * @hide
+ * This parcelable constitutes and excerpt from the PackageManager's PackageInfo for the purpose of
+ * key attestation. It is part of the KeyAttestationApplicationId, which is used by
+ * keystore to identify the caller of the keystore API towards a remote party.
+ */
+parcelable KeyAttestationPackageInfo {
+    String packageName;
+
+    long versionCode;
+
+    Signature[] signatures;
+}
diff --git a/keystore/aaid/aidl/android/security/keystore/Signature.aidl b/keystore/aaid/aidl/android/security/keystore/Signature.aidl
new file mode 100644
index 0000000..800499a
--- /dev/null
+++ b/keystore/aaid/aidl/android/security/keystore/Signature.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.security.keystore;
+
+/**
+ * @hide
+ * Represents a signature data read from the package file. Extracted from from the PackageManager's
+ * PackageInfo for the purpose of key attestation. It is part of the KeyAttestationPackageInfo,
+ * which is used by keystore to identify the caller of the keystore API towards a remote party.
+ */
+parcelable Signature {
+    /**
+     * Represents signing certificate data associated with application package, signatures are
+     * expected to be a hex-encoded ASCII string representing valid X509 certificate.
+     */
+    byte[] data;
+}
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 0f3488b..31c2eb2 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -28,8 +28,8 @@
 import android.util.Log;
 
 /**
- * @hide This is the client side for IKeystoreUserManager AIDL.
- * It shall only be used by the LockSettingsService.
+ * @hide This is the client side for IKeystoreMaintenance AIDL.
+ * It is used mainly by LockSettingsService.
  */
 public class AndroidKeyStoreMaintenance {
     private static final String TAG = "AndroidKeyStoreMaintenance";
@@ -66,7 +66,7 @@
     }
 
     /**
-     * Informs Keystore 2.0 about removing a usergit mer
+     * Informs Keystore 2.0 about removing a user
      *
      * @param userId - Android user id of the user being removed
      * @return 0 if successful or a {@code ResponseCode}
@@ -91,7 +91,7 @@
      *
      * @param userId   - Android user id of the user
      * @param password - a secret derived from the synthetic password provided by the
-     *                 LockSettingService
+     *                 LockSettingsService
      * @return 0 if successful or a {@code ResponseCode}
      * @hide
      */
@@ -110,7 +110,7 @@
     }
 
     /**
-     * Informs Keystore 2.0 that an app was uninstalled and the corresponding namspace is to
+     * Informs Keystore 2.0 that an app was uninstalled and the corresponding namespace is to
      * be cleared.
      */
     public static int clearNamespace(@Domain int domain, long namespace) {
@@ -172,10 +172,10 @@
      *                    namespace.
      *
      * @return * 0 on success
-     *         * KEY_NOT_FOUND if the source did not exists.
+     *         * KEY_NOT_FOUND if the source did not exist.
      *         * PERMISSION_DENIED if any of the required permissions was missing.
      *         * INVALID_ARGUMENT if the destination was occupied or any domain value other than
-     *                   the allowed once were specified.
+     *                   the allowed ones was specified.
      *         * SYSTEM_ERROR if an unexpected error occurred.
      */
     public static int migrateKeyNamespace(KeyDescriptor source, KeyDescriptor destination) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index c55a781..11278e8 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -43,6 +43,7 @@
 import java.security.interfaces.RSAPublicKey;
 
 import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
 import javax.crypto.Mac;
 import javax.crypto.SecretKey;
 
@@ -181,6 +182,8 @@
             spi = ((Mac) cryptoPrimitive).getCurrentSpi();
         } else if (cryptoPrimitive instanceof Cipher) {
             spi = ((Cipher) cryptoPrimitive).getCurrentSpi();
+        } else if (cryptoPrimitive instanceof KeyAgreement) {
+            spi = ((KeyAgreement) cryptoPrimitive).getCurrentSpi();
         } else {
             throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive
                     + ". Supported: Signature, Mac, Cipher");
diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
index b6e743a..ed2ff2d 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp
+++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
@@ -37,7 +37,7 @@
         "androidx.test.rules",
         "androidx.test.ext.junit",
         "mockito-target-extended-minus-junit4",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "platform-test-annotations",
     ],
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index d55a41f..7c0d0e3 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -5,4 +5,18 @@
     namespace: "multitasking"
     description: "An Example Flag"
     bug: "300136750"
-}
\ No newline at end of file
+}
+
+flag {
+    name: "enable_app_pairs"
+    namespace: "multitasking"
+    description: "Enables the ability to create and save app pairs to the Home screen"
+    bug: "274835596"
+}
+
+flag {
+    name: "desktop_windowing"
+    namespace: "multitasking"
+    description: "Enables desktop windowing"
+    bug: "304778354"
+}
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
new file mode 100644
index 0000000..ee9f070
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="@dimen/desktop_mode_handle_menu_width"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/desktop_mode_handle_menu_app_info_pill_height"
+        android:layout_marginTop="@dimen/desktop_mode_handle_menu_margin_top"
+        android:layout_marginStart="1dp"
+        android:elevation="1dp"
+        android:orientation="horizontal"
+        android:background="@drawable/desktop_mode_decor_handle_menu_background"
+        android:gravity="center_vertical">
+
+        <ImageView
+            android:id="@+id/application_icon"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_marginStart="14dp"
+            android:layout_marginEnd="14dp"
+            android:contentDescription="@string/app_icon_text"/>
+
+        <TextView
+            android:id="@+id/application_name"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            tools:text="Gmail"
+            android:textColor="?androidprv:attr/materialColorOnSurface"
+            android:textSize="14sp"
+            android:textFontWeight="500"
+            android:lineHeight="20dp"
+            android:textStyle="normal"
+            android:layout_weight="1"/>
+
+        <ImageButton
+            android:id="@+id/collapse_menu_button"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:padding="4dp"
+            android:layout_marginEnd="14dp"
+            android:layout_marginStart="14dp"
+            android:contentDescription="@string/collapse_menu_text"
+            android:src="@drawable/ic_baseline_expand_more_24"
+            android:rotation="180"
+            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:background="?android:selectableItemBackgroundBorderless"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/desktop_mode_handle_menu_windowing_pill_height"
+        android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin"
+        android:layout_marginStart="1dp"
+        android:orientation="horizontal"
+        android:elevation="1dp"
+        android:background="@drawable/desktop_mode_decor_handle_menu_background"
+        android:gravity="center_vertical">
+
+        <ImageButton
+            android:id="@+id/fullscreen_button"
+            android:layout_marginEnd="4dp"
+            android:contentDescription="@string/fullscreen_text"
+            android:src="@drawable/desktop_mode_ic_handle_menu_fullscreen"
+            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:layout_weight="1"
+            style="@style/DesktopModeHandleMenuWindowingButton"/>
+
+        <ImageButton
+            android:id="@+id/split_screen_button"
+            android:layout_marginStart="4dp"
+            android:layout_marginEnd="4dp"
+            android:contentDescription="@string/split_screen_text"
+            android:src="@drawable/desktop_mode_ic_handle_menu_splitscreen"
+            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:layout_weight="1"
+            style="@style/DesktopModeHandleMenuWindowingButton"/>
+
+        <ImageButton
+            android:id="@+id/floating_button"
+            android:layout_marginStart="4dp"
+            android:layout_marginEnd="4dp"
+            android:contentDescription="@string/float_button_text"
+            android:src="@drawable/desktop_mode_ic_handle_menu_floating"
+            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:layout_weight="1"
+            style="@style/DesktopModeHandleMenuWindowingButton"/>
+
+        <ImageButton
+            android:id="@+id/desktop_button"
+            android:layout_marginStart="4dp"
+            android:contentDescription="@string/desktop_text"
+            android:src="@drawable/desktop_mode_ic_handle_menu_desktop"
+            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:layout_weight="1"
+            style="@style/DesktopModeHandleMenuWindowingButton"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/desktop_mode_handle_menu_more_actions_pill_height"
+        android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin"
+        android:layout_marginStart="1dp"
+        android:orientation="vertical"
+        android:elevation="1dp"
+        android:background="@drawable/desktop_mode_decor_handle_menu_background">
+
+        <Button
+            android:id="@+id/screenshot_button"
+            android:contentDescription="@string/screenshot_text"
+            android:text="@string/screenshot_text"
+            android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot"
+            android:drawableTint="?androidprv:attr/materialColorOnSurface"
+            style="@style/DesktopModeHandleMenuActionButton"/>
+
+        <Button
+            android:id="@+id/select_button"
+            android:contentDescription="@string/select_text"
+            android:text="@string/select_text"
+            android:drawableStart="@drawable/desktop_mode_ic_handle_menu_select"
+            android:drawableTint="?androidprv:attr/materialColorOnSurface"
+            style="@style/DesktopModeHandleMenuActionButton"/>
+
+    </LinearLayout>
+</LinearLayout>
+
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml
deleted file mode 100644
index c2ee306..0000000
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2023 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.
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="@dimen/desktop_mode_handle_menu_width"
-    android:layout_height="@dimen/desktop_mode_handle_menu_app_info_pill_height"
-    android:orientation="horizontal"
-    android:background="@drawable/desktop_mode_decor_handle_menu_background"
-    android:gravity="center_vertical">
-
-    <ImageView
-        android:id="@+id/application_icon"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_marginStart="14dp"
-        android:layout_marginEnd="14dp"
-        android:contentDescription="@string/app_icon_text"/>
-
-    <TextView
-        android:id="@+id/application_name"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        tools:text="Gmail"
-        android:textColor="?androidprv:attr/materialColorOnSurface"
-        android:textSize="14sp"
-        android:textFontWeight="500"
-        android:lineHeight="20dp"
-        android:textStyle="normal"
-        android:layout_weight="1"/>
-
-    <ImageButton
-        android:id="@+id/collapse_menu_button"
-        android:layout_width="32dp"
-        android:layout_height="32dp"
-        android:padding="4dp"
-        android:layout_marginEnd="14dp"
-        android:layout_marginStart="14dp"
-        android:contentDescription="@string/collapse_menu_text"
-        android:src="@drawable/ic_baseline_expand_more_24"
-        android:rotation="180"
-        android:tint="?androidprv:attr/materialColorOnSurface"
-        android:background="?android:selectableItemBackgroundBorderless"/>
-</LinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml
deleted file mode 100644
index e637671..0000000
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2023 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.
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:layout_width="@dimen/desktop_mode_handle_menu_width"
-    android:layout_height="@dimen/desktop_mode_handle_menu_more_actions_pill_height"
-    android:orientation="vertical"
-    android:background="@drawable/desktop_mode_decor_handle_menu_background">
-
-    <Button
-        android:id="@+id/screenshot_button"
-        android:contentDescription="@string/screenshot_text"
-        android:text="@string/screenshot_text"
-        android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot"
-        android:drawableTint="?androidprv:attr/materialColorOnSurface"
-        style="@style/DesktopModeHandleMenuActionButton"/>
-
-    <Button
-        android:id="@+id/select_button"
-        android:contentDescription="@string/select_text"
-        android:text="@string/select_text"
-        android:drawableStart="@drawable/desktop_mode_ic_handle_menu_select"
-        android:drawableTint="?androidprv:attr/materialColorOnSurface"
-        style="@style/DesktopModeHandleMenuActionButton"/>
-    <Button
-        android:id="@+id/close_button"
-        android:contentDescription="@string/close_text"
-        android:text="@string/close_text"
-        android:drawableStart="@drawable/desktop_mode_ic_handle_menu_close"
-        android:drawableTint="?androidprv:attr/materialColorOnSurface"
-        style="@style/DesktopModeHandleMenuActionButton"/>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml
deleted file mode 100644
index c4b688d..0000000
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2023 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.
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:layout_width="@dimen/desktop_mode_handle_menu_width"
-    android:layout_height="@dimen/desktop_mode_handle_menu_windowing_pill_height"
-    android:orientation="horizontal"
-    android:background="@drawable/desktop_mode_decor_handle_menu_background"
-    android:gravity="center_vertical">
-
-    <ImageButton
-        android:id="@+id/fullscreen_button"
-        android:layout_marginEnd="4dp"
-        android:contentDescription="@string/fullscreen_text"
-        android:src="@drawable/desktop_mode_ic_handle_menu_fullscreen"
-        android:tint="?androidprv:attr/materialColorOnSurface"
-        android:layout_weight="1"
-        style="@style/DesktopModeHandleMenuWindowingButton"/>
-
-    <ImageButton
-        android:id="@+id/split_screen_button"
-        android:layout_marginStart="4dp"
-        android:layout_marginEnd="4dp"
-        android:contentDescription="@string/split_screen_text"
-        android:src="@drawable/desktop_mode_ic_handle_menu_splitscreen"
-        android:tint="?androidprv:attr/materialColorOnSurface"
-        android:layout_weight="1"
-        style="@style/DesktopModeHandleMenuWindowingButton"/>
-
-    <ImageButton
-        android:id="@+id/floating_button"
-        android:layout_marginStart="4dp"
-        android:layout_marginEnd="4dp"
-        android:contentDescription="@string/float_button_text"
-        android:src="@drawable/desktop_mode_ic_handle_menu_floating"
-        android:tint="?androidprv:attr/materialColorOnSurface"
-        android:layout_weight="1"
-        style="@style/DesktopModeHandleMenuWindowingButton"/>
-
-    <ImageButton
-        android:id="@+id/desktop_button"
-        android:layout_marginStart="4dp"
-        android:contentDescription="@string/desktop_text"
-        android:src="@drawable/desktop_mode_ic_handle_menu_desktop"
-        android:tint="?androidprv:attr/materialColorOnSurface"
-        android:layout_weight="1"
-        style="@style/DesktopModeHandleMenuWindowingButton"/>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 97a9d48..7436400 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -58,6 +58,9 @@
          if a custom action is present before closing it. -->
     <integer name="config_pipForceCloseDelay">1000</integer>
 
+    <!-- Allow PIP to resize via pinch gesture. -->
+    <bool name="config_pipEnablePinchResize">true</bool>
+
     <!-- Animation duration when using long press on recents to dock -->
     <integer name="long_press_dock_anim_duration">250</integer>
 
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 705e387..1f6f7ae 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -143,7 +143,9 @@
     <dimen name="bubble_expanded_view_padding">16dp</dimen>
     <!-- Padding for the edge of the expanded view that is closest to the edge of the screen used
          when displaying in landscape on a large screen. -->
-    <dimen name="bubble_expanded_view_largescreen_landscape_padding">128dp</dimen>
+    <dimen name="bubble_expanded_view_largescreen_landscape_padding">102dp</dimen>
+    <!-- The width of the expanded view on large screens. -->
+    <dimen name="bubble_expanded_view_largescreen_width">540dp</dimen>
     <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
          a slight touch slop around the expanded view. -->
     <dimen name="bubble_expanded_view_slop">8dp</dimen>
@@ -434,11 +436,11 @@
     <!-- The height of the handle menu's "Windowing" pill in desktop mode. -->
     <dimen name="desktop_mode_handle_menu_windowing_pill_height">52dp</dimen>
 
-    <!-- The height of the handle menu's "More Actions" pill in desktop mode, but not freeform. -->
-    <dimen name="desktop_mode_handle_menu_more_actions_pill_height">104dp</dimen>
+    <!-- The height of the handle menu's "More Actions" pill in desktop mode. -->
+    <dimen name="desktop_mode_handle_menu_more_actions_pill_height">52dp</dimen>
 
-    <!-- The height of the handle menu's "More Actions" pill in freeform desktop windowing mode. -->
-    <dimen name="desktop_mode_handle_menu_more_actions_pill_freeform_height">52dp</dimen>
+    <!-- The height of the handle menu in desktop mode. -->
+    <dimen name="desktop_mode_handle_menu_height">328dp</dimen>
 
     <!-- The top margin of the handle menu in desktop mode. -->
     <dimen name="desktop_mode_handle_menu_margin_top">4dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
index 34bf9e0..2e5448a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
@@ -18,6 +18,7 @@
 
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
 
+import android.annotation.SuppressLint;
 import android.app.WindowConfiguration;
 import android.util.SparseArray;
 import android.view.SurfaceControl;
@@ -29,6 +30,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.sysui.ShellInit;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -44,9 +46,14 @@
     /** Display area leashes, which is mapped by display IDs. */
     private final SparseArray<SurfaceControl> mLeashes = new SparseArray<>();
 
-    public RootDisplayAreaOrganizer(Executor executor) {
+    public RootDisplayAreaOrganizer(@NonNull Executor executor, @NonNull ShellInit shellInit) {
         super(executor);
-        List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_ROOT);
+        shellInit.addInitCallback(this::onInit, this);
+    }
+
+    @SuppressLint("MissingPermission") // Only called by SysUI.
+    private void onInit() {
+        final List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_ROOT);
         for (int i = infos.size() - 1; i >= 0; --i) {
             onDisplayAreaAppeared(infos.get(i).getDisplayAreaInfo(), infos.get(i).getLeash());
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
index 410ae78d..ab61a48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
@@ -18,6 +18,7 @@
 
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
 
+import android.annotation.SuppressLint;
 import android.annotation.UiContext;
 import android.app.ResourcesManager;
 import android.content.Context;
@@ -32,11 +33,13 @@
 import android.window.DisplayAreaAppearedInfo;
 import android.window.DisplayAreaInfo;
 import android.window.DisplayAreaOrganizer;
+import android.window.SystemPerformanceHinter;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.sysui.ShellInit;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -58,12 +61,27 @@
     /** {@link DisplayAreaContext} list, which is mapped by display IDs. */
     private final SparseArray<DisplayAreaContext> mDisplayAreaContexts = new SparseArray<>();
 
+    private final SystemPerformanceHinter.DisplayRootProvider mPerfRootProvider =
+            new SystemPerformanceHinter.DisplayRootProvider() {
+                @Override
+                public SurfaceControl getRootForDisplay(int displayId) {
+                    return mLeashes.get(displayId);
+                }
+            };
+
     private final Context mContext;
 
-    public RootTaskDisplayAreaOrganizer(Executor executor, Context context) {
+    public RootTaskDisplayAreaOrganizer(@NonNull Executor executor, @NonNull Context context,
+            @NonNull ShellInit shellInit) {
         super(executor);
         mContext = context;
-        List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_DEFAULT_TASK_CONTAINER);
+        shellInit.addInitCallback(this::onInit, this);
+    }
+
+    @SuppressLint("MissingPermission") // Only called by SysUI.
+    private void onInit() {
+        final List<DisplayAreaAppearedInfo> infos =
+                registerOrganizer(FEATURE_DEFAULT_TASK_CONTAINER);
         for (int i = infos.size() - 1; i >= 0; --i) {
             onDisplayAreaAppeared(infos.get(i).getDisplayAreaInfo(), infos.get(i).getLeash());
         }
@@ -229,6 +247,11 @@
         return mDisplayAreaContexts.get(displayId);
     }
 
+    @NonNull
+    public SystemPerformanceHinter.DisplayRootProvider getPerformanceRootProvider() {
+        return mPerfRootProvider;
+    }
+
     public void dump(@NonNull PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         final String childPrefix = innerPrefix + "  ";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index f1ee8fa..a67821b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -318,7 +318,7 @@
     /**
      * Animates the dot to the given scale, running the optional callback when the animation ends.
      */
-    private void animateDotScale(float toScale, @Nullable Runnable after) {
+    public void animateDotScale(float toScale, @Nullable Runnable after) {
         mDotIsAnimating = true;
 
         // Don't restart the animation if we're already animating to the given value.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index df19757..dc099d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -27,6 +27,7 @@
 import android.graphics.drawable.InsetDrawable
 import android.util.PathParser
 import android.view.LayoutInflater
+import android.view.View.VISIBLE
 import android.widget.FrameLayout
 import com.android.launcher3.icons.BubbleIconFactory
 import com.android.wm.shell.R
@@ -156,7 +157,9 @@
 
     fun setShowDot(show: Boolean) {
         showDot = show
-        overflowBtn?.updateDotVisibility(true /* animate */)
+        if (overflowBtn?.visibility == VISIBLE) {
+            overflowBtn?.updateDotVisibility(true /* animate */)
+        }
     }
 
     /** Creates the expanded view for bubbles showing in the stack view. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index ea7053d..17e06e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -54,10 +54,6 @@
     public static final float FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN = 0.3f;
     /** The max percent of screen width to use for the flyout on phone. */
     public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f;
-    /** The percent of screen width for the expanded view on a large screen. **/
-    private static final float EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT = 0.48f;
-    /** The percent of screen width for the expanded view on a large screen. **/
-    private static final float EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT = 0.70f;
     /** The percent of screen width for the expanded view on a small tablet. **/
     private static final float EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT = 0.72f;
     /** The percent of screen width for the expanded view when shown in the bubble bar. **/
@@ -95,6 +91,7 @@
     private int mPointerWidth;
     private int mPointerHeight;
     private int mPointerOverlap;
+    private int mManageButtonHeightIncludingMargins;
     private int mManageButtonHeight;
     private int mOverflowHeight;
     private int mMinimumFlyoutWidthLargeScreen;
@@ -176,21 +173,20 @@
             mExpandedViewLargeScreenWidth = (int) (bounds.width()
                     * EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT);
         } else {
-            mExpandedViewLargeScreenWidth = isLandscape()
-                    ? (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT)
-                    : (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT);
+            mExpandedViewLargeScreenWidth =
+                    res.getDimensionPixelSize(R.dimen.bubble_expanded_view_largescreen_width);
         }
         if (mIsLargeScreen) {
-            if (isLandscape() && !mIsSmallTablet) {
+            if (mIsSmallTablet) {
+                final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2;
+                mExpandedViewLargeScreenInsetClosestEdge = centeredInset;
+                mExpandedViewLargeScreenInsetFurthestEdge = centeredInset;
+            } else {
                 mExpandedViewLargeScreenInsetClosestEdge = res.getDimensionPixelSize(
                         R.dimen.bubble_expanded_view_largescreen_landscape_padding);
                 mExpandedViewLargeScreenInsetFurthestEdge = bounds.width()
                         - mExpandedViewLargeScreenInsetClosestEdge
                         - mExpandedViewLargeScreenWidth;
-            } else {
-                final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2;
-                mExpandedViewLargeScreenInsetClosestEdge = centeredInset;
-                mExpandedViewLargeScreenInsetFurthestEdge = centeredInset;
             }
         } else {
             mExpandedViewLargeScreenInsetClosestEdge = mExpandedViewPadding;
@@ -202,7 +198,9 @@
         mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
         mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
         mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap);
-        mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height);
+        mManageButtonHeightIncludingMargins =
+                res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height);
+        mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
         mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
         mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
         mMinimumFlyoutWidthLargeScreen = res.getDimensionPixelSize(
@@ -420,7 +418,7 @@
         int pointerSize = showBubblesVertically()
                 ? mPointerWidth
                 : (mPointerHeight + mPointerMargin);
-        int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeight;
+        int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins;
         return getAvailableRect().height()
                 - expandedContainerY
                 - paddingTop
@@ -438,6 +436,15 @@
             // overflow in landscape on phone is max
             return MAX_HEIGHT;
         }
+
+        if (mIsLargeScreen && !mIsSmallTablet && !isOverflow) {
+            // the expanded view height on large tablets is calculated based on the shortest screen
+            // size and is the same in both portrait and landscape
+            int maxVerticalInset = Math.max(mInsets.top, mInsets.bottom);
+            int shortestScreenSide = Math.min(mScreenRect.height(), mScreenRect.width());
+            return shortestScreenSide - 2 * maxVerticalInset - mManageButtonHeight;
+        }
+
         float desiredHeight = isOverflow
                 ? mOverflowHeight
                 : ((Bubble) bubble).getDesiredHeight(mContext);
@@ -466,7 +473,8 @@
             return topAlignment;
         }
         // If we're here, we're showing vertically & developer has made height less than maximum.
-        int manageButtonHeight = isOverflow ? mExpandedViewPadding : mManageButtonHeight;
+        int manageButtonHeight =
+                isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins;
         float pointerPosition = getPointerPosition(bubblePosition);
         float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight;
         float topIfCentered = pointerPosition - (expandedViewHeight / 2);
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 c124b53..2241c34 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
@@ -1864,6 +1864,14 @@
                 : GONE);
     }
 
+    private void updateOverflowDotVisibility(boolean expanding) {
+        if (mBubbleOverflow.showDot()) {
+            mBubbleOverflow.getIconView().animateDotScale(expanding ? 1 : 0f, () -> {
+                mBubbleOverflow.setVisible(expanding ? VISIBLE : GONE);
+            });
+        }
+    }
+
     // via BubbleData.Listener
     void updateBubble(Bubble bubble) {
         animateInFlyoutForBubble(bubble);
@@ -2274,6 +2282,7 @@
             if (mIsExpanded && mExpandedBubble.getExpandedView() != null) {
                 maybeShowManageEdu();
             }
+            updateOverflowDotVisibility(true /* expanding */);
         } /* after */);
         int index;
         if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
@@ -2405,11 +2414,15 @@
         // since we're about to animate collapsed.
         mExpandedAnimationController.notifyPreparingToCollapse();
 
+        updateOverflowDotVisibility(false /* expanding */);
         final Runnable collapseBackToStack = () -> mExpandedAnimationController.collapseBackToStack(
                 mStackAnimationController
                         .getStackPositionAlongNearestHorizontalEdge()
                 /* collapseTo */,
-                () -> mBubbleContainer.setActiveController(mStackAnimationController));
+                () -> {
+                    mBubbleContainer.setActiveController(mStackAnimationController);
+                    updateOverflowVisibility();
+                });
 
         final Runnable after = () -> {
             final BubbleViewProvider previouslySelected = mExpandedBubble;
@@ -2424,7 +2437,6 @@
                 Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
                         mExpandedBubble));
             }
-            updateOverflowVisibility();
             updateZOrder();
             updateBadges(true /* setBadgeForCollapsedStack */);
             afterExpandedViewAnimation();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 4d7042b..738c94e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -34,6 +34,8 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BadgedImageView;
+import com.android.wm.shell.bubbles.BubbleOverflow;
 import com.android.wm.shell.bubbles.BubblePositioner;
 import com.android.wm.shell.bubbles.BubbleStackView;
 import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -63,6 +65,12 @@
     /** Damping ratio for expand/collapse spring. */
     private static final float DAMPING_RATIO_MEDIUM_LOW_BOUNCY = 0.65f;
 
+    /**
+     * Damping ratio for the overflow bubble spring; this is less bouncy so it doesn't bounce behind
+     * the top bubble when it goes to disappear.
+     */
+    private static final float DAMPING_RATIO_OVERFLOW_BOUNCY = 0.90f;
+
     /** Stiffness for the expand/collapse path-following animation. */
     private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 400;
 
@@ -274,9 +282,14 @@
                 // of the screen where the bubble will be stacked.
                 path.lineTo(stackedX, p.y);
 
+                // The overflow should animate to the collapse point, so 0 offset.
+                final boolean isOverflow = bubble instanceof BadgedImageView
+                        && BubbleOverflow.KEY.equals(((BadgedImageView) bubble).getKey());
+                final float offsetY = isOverflow
+                        ? 0
+                        : Math.min(index, NUM_VISIBLE_WHEN_RESTING - 1) * mStackOffsetPx;
                 // Then, draw a line down to the stack position.
-                path.lineTo(stackedX, mCollapsePoint.y
-                        + Math.min(index, NUM_VISIBLE_WHEN_RESTING - 1) * mStackOffsetPx);
+                path.lineTo(stackedX, mCollapsePoint.y + offsetY);
             }
 
             // The lead bubble should be the bubble with the longest distance to travel when we're
@@ -505,8 +518,12 @@
 
     @Override
     SpringForce getSpringForce(DynamicAnimation.ViewProperty property, View view) {
+        boolean isOverflow = (view instanceof BadgedImageView)
+                && BubbleOverflow.KEY.equals(((BadgedImageView) view).getKey());
         return new SpringForce()
-                .setDampingRatio(DAMPING_RATIO_MEDIUM_LOW_BOUNCY)
+                .setDampingRatio(isOverflow
+                        ? DAMPING_RATIO_OVERFLOW_BOUNCY
+                        : DAMPING_RATIO_MEDIUM_LOW_BOUNCY)
                 .setStiffness(SpringForce.STIFFNESS_LOW);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt
index 67dc642..e1dea3b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt
@@ -25,7 +25,8 @@
     private var _isBubbleBarEnabled =
             SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false)
 
-    override val isBubbleBarEnabled = _isBubbleBarEnabled
+    override val isBubbleBarEnabled
+        get() = _isBubbleBarEnabled
 
     override fun refresh() {
         _isBubbleBarEnabled = SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/common/OWNERS
index 7af0389..6519eee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/OWNERS
@@ -1 +1,2 @@
 madym@google.com
+hwwang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 5e42782..e9344ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -203,7 +203,7 @@
                     + "SystemWindow:" + view);
             return null;
         }
-        return root.getFocusGrantToken();
+        return root.getInputTransferToken();
     }
 
     private class PerDisplay {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TvWindowMenuActionButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TvWindowMenuActionButton.java
index 931cf0c..c6c9b35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TvWindowMenuActionButton.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TvWindowMenuActionButton.java
@@ -94,6 +94,10 @@
         mCurrentIcon = icon;
         // Remove old image while waiting for the new one to load.
         mIconImageView.setImageDrawable(null);
+        if (icon.getType() == Icon.TYPE_URI || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+            // Disallow loading icon from content URI
+            return;
+        }
         icon.loadDrawableAsync(mContext, d -> {
             // The image hasn't been set any other way and the drawable belongs to the most
             // recently set Icon.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
index 3b32b6c..d520ff7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
@@ -126,12 +126,22 @@
     private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
     private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>();
 
+    // the size of the current bounds relative to the max size spec
+    private float mBoundsScale;
+
     public PipBoundsState(@NonNull Context context, @NonNull SizeSpecSource sizeSpecSource,
             @NonNull PipDisplayLayoutState pipDisplayLayoutState) {
         mContext = context;
         reloadResources();
         mSizeSpecSource = sizeSpecSource;
         mPipDisplayLayoutState = pipDisplayLayoutState;
+
+        // Update the relative proportion of the bounds compared to max possible size. Max size
+        // spec takes the aspect ratio of the bounds into account, so both width and height
+        // scale by the same factor.
+        addPipExclusionBoundsChangeCallback((bounds) -> {
+            mBoundsScale = Math.min((float) bounds.width() / mMaxSize.x, 1.0f);
+        });
     }
 
     /** Reloads the resources. */
@@ -160,6 +170,15 @@
         return new Rect(mBounds);
     }
 
+    /**
+     * Get the scale of the current bounds relative to the maximum size possible.
+     *
+     * @return 1.0 if {@link PipBoundsState#getBounds()} equals {@link PipBoundsState#getMaxSize()}.
+     */
+    public float getBoundsScale() {
+        return mBoundsScale;
+    }
+
     /** Returns the current movement bounds. */
     @NonNull
     public Rect getMovementBounds() {
@@ -622,6 +641,9 @@
         pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
         pw.println(innerPrefix + "mHasUserMovedPip=" + mHasUserMovedPip);
         pw.println(innerPrefix + "mHasUserResizedPip=" + mHasUserResizedPip);
+        pw.println(innerPrefix + "mMinSize=" + mMinSize);
+        pw.println(innerPrefix + "mMaxSize=" + mMaxSize);
+        pw.println(innerPrefix + "mBoundsScale" + mBoundsScale);
         if (mPipReentryState == null) {
             pw.println(innerPrefix + "mPipReentryState=null");
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 998cd5d..c51af46 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -25,6 +25,7 @@
 import android.os.SystemProperties;
 import android.view.IWindowManager;
 import android.view.accessibility.AccessibilityManager;
+import android.window.SystemPerformanceHinter;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.launcher3.icons.IconProvider;
@@ -85,6 +86,7 @@
 import com.android.wm.shell.keyguard.KeyguardTransitions;
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.onehanded.OneHandedController;
+import com.android.wm.shell.performance.PerfHintController;
 import com.android.wm.shell.recents.RecentTasks;
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.recents.RecentsTransitionHandler;
@@ -108,13 +110,13 @@
 import com.android.wm.shell.unfold.UnfoldTransitionHandler;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
-import java.util.Optional;
-
 import dagger.BindsOptionalOf;
 import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
+import java.util.Optional;
+
 /**
  * Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only
  * accessible from components within the WM subcomponent (can be explicitly exposed to the
@@ -296,6 +298,17 @@
         return new LaunchAdjacentController(syncQueue);
     }
 
+    @WMSingleton
+    @Provides
+    static SystemPerformanceHinter provideSystemPerformanceHinter(Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            RootTaskDisplayAreaOrganizer rootTdaOrganizer) {
+        final PerfHintController perfHintController =
+                new PerfHintController(context, shellInit, shellCommandHandler, rootTdaOrganizer);
+        return perfHintController.getHinter();
+    }
+
     //
     // Back animation
     //
@@ -645,15 +658,15 @@
     @WMSingleton
     @Provides
     static RootTaskDisplayAreaOrganizer provideRootTaskDisplayAreaOrganizer(
-            @ShellMainThread ShellExecutor mainExecutor, Context context) {
-        return new RootTaskDisplayAreaOrganizer(mainExecutor, context);
+            @ShellMainThread ShellExecutor mainExecutor, Context context, ShellInit shellInit) {
+        return new RootTaskDisplayAreaOrganizer(mainExecutor, context, shellInit);
     }
 
     @WMSingleton
     @Provides
     static RootDisplayAreaOrganizer provideRootDisplayAreaOrganizer(
-            @ShellMainThread ShellExecutor mainExecutor) {
-        return new RootDisplayAreaOrganizer(mainExecutor);
+            @ShellMainThread ShellExecutor mainExecutor, ShellInit shellInit) {
+        return new RootDisplayAreaOrganizer(mainExecutor, shellInit);
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 11aa0546..5dfba5e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -494,13 +494,14 @@
             ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
             @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
             LaunchAdjacentController launchAdjacentController,
+            RecentsTransitionHandler recentsTransitionHandler,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
         return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,
                 displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
                 transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler,
                 toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository,
-                launchAdjacentController, mainExecutor);
+                launchAdjacentController, recentsTransitionHandler, mainExecutor);
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index af97cf6..8a64037 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -23,7 +23,7 @@
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.dagger.WMShellBaseModule;
 import com.android.wm.shell.dagger.WMSingleton;
-import com.android.wm.shell.pip2.PipTransition;
+import com.android.wm.shell.pip2.phone.PipTransition;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
index 570f0a3..f2631ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
@@ -19,6 +19,7 @@
 import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.dagger.WMSingleton;
 import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip2.phone.PipTransition;
 
 import dagger.Module;
 import dagger.Provides;
@@ -36,7 +37,7 @@
     @Provides
     static PipTransitionController providePipTransitionController(
             com.android.wm.shell.pip.PipTransition legacyPipTransition,
-            com.android.wm.shell.pip2.PipTransition newPipTransition) {
+            PipTransition newPipTransition) {
         if (PipUtils.isPip2ExperimentEnabled()) {
             return newPipTransition;
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 09ba4f7..412a5b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -60,6 +60,8 @@
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
 import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.recents.RecentsTransitionHandler
+import com.android.wm.shell.recents.RecentsTransitionStateListener
 import com.android.wm.shell.splitscreen.SplitScreenController
 import com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ENTER_DESKTOP
 import com.android.wm.shell.sysui.ShellCommandHandler
@@ -68,7 +70,6 @@
 import com.android.wm.shell.sysui.ShellSharedConstants
 import com.android.wm.shell.transition.OneShotRemoteHandler
 import com.android.wm.shell.transition.Transitions
-import com.android.wm.shell.transition.Transitions.TransitionHandler
 import com.android.wm.shell.util.KtProtoLog
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
 import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
@@ -93,6 +94,7 @@
         ToggleResizeDesktopTaskTransitionHandler,
         private val desktopModeTaskRepository: DesktopModeTaskRepository,
         private val launchAdjacentController: LaunchAdjacentController,
+        private val recentsTransitionHandler: RecentsTransitionHandler,
         @ShellMainThread private val mainExecutor: ShellExecutor
 ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler {
 
@@ -119,6 +121,8 @@
             com.android.wm.shell.R.dimen.desktop_mode_transition_area_width
         )
 
+    private var recentsAnimationRunning = false
+
     // This is public to avoid cyclic dependency; it is set by SplitScreenController
     lateinit var splitScreenController: SplitScreenController
 
@@ -139,6 +143,19 @@
         )
         transitions.addHandler(this)
         desktopModeTaskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor)
+
+        recentsTransitionHandler.addTransitionStateListener(
+            object : RecentsTransitionStateListener {
+                override fun onAnimationStateChanged(running: Boolean) {
+                    KtProtoLog.v(
+                        WM_SHELL_DESKTOP_MODE,
+                        "DesktopTasksController: recents animation state changed running=%b",
+                        running
+                    )
+                    recentsAnimationRunning = running
+                }
+            }
+        )
     }
 
     /** Show all tasks, that are part of the desktop, on top of launcher */
@@ -644,6 +661,10 @@
         val triggerTask = request.triggerTask
         val shouldHandleRequest =
             when {
+                recentsAnimationRunning -> {
+                    reason = "recents animation is running"
+                    false
+                }
                 // Only handle open or to front transitions
                 request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> {
                     reason = "transition type not handled (${request.type})"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt
new file mode 100644
index 0000000..f7977f8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.performance
+
+import android.content.Context
+import android.os.PerformanceHintManager
+import android.os.Process
+import android.window.SystemPerformanceHinter
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.sysui.ShellCommandHandler
+import com.android.wm.shell.sysui.ShellInit
+import java.io.PrintWriter
+import java.util.concurrent.TimeUnit
+
+/**
+ * Manages the performance hints to the system.
+ */
+class PerfHintController(private val mContext: Context,
+                         shellInit: ShellInit,
+                         private val mShellCommandHandler: ShellCommandHandler,
+                         rootTdaOrganizer: RootTaskDisplayAreaOrganizer) {
+
+    // The system perf hinter
+    val hinter: SystemPerformanceHinter
+
+    init {
+        hinter = SystemPerformanceHinter(mContext,
+                rootTdaOrganizer.performanceRootProvider)
+        shellInit.addInitCallback(this::onInit, this)
+    }
+
+    private fun onInit() {
+        mShellCommandHandler.addDumpCallback(this::dump, this)
+        val perfHintMgr = mContext.getSystemService(PerformanceHintManager::class.java)
+        val adpfSession = perfHintMgr!!.createHintSession(intArrayOf(Process.myTid()),
+                TimeUnit.SECONDS.toNanos(1))
+        hinter.setAdpfSession(adpfSession)
+    }
+
+    fun dump(pw: PrintWriter, prefix: String?) {
+        hinter.dump(pw, prefix)
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 1064867..63f20fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -797,21 +797,15 @@
                     mPipBoundsAlgorithm.getMovementBounds(postChangeBounds),
                     mPipBoundsState.getStashedState());
 
-            // Scale PiP on density dpi change, so it appears to be the same size physically.
-            final boolean densityDpiChanged =
-                    mPipDisplayLayoutState.getDisplayLayout().densityDpi() != 0
-                    && (mPipDisplayLayoutState.getDisplayLayout().densityDpi()
-                            != layout.densityDpi());
-            if (densityDpiChanged) {
-                final float scale = (float) layout.densityDpi()
-                        / mPipDisplayLayoutState.getDisplayLayout().densityDpi();
-                postChangeBounds.set(0, 0,
-                        (int) (postChangeBounds.width() * scale),
-                        (int) (postChangeBounds.height() * scale));
-            }
-
             updateDisplayLayout.run();
 
+            // Resize the PiP bounds to be at the same scale relative to the new size spec. For
+            // example, if PiP was resized to 90% of the maximum size on the previous layout,
+            // make sure it is 90% of the new maximum size spec.
+            postChangeBounds.set(0, 0,
+                    (int) (mPipBoundsState.getMaxSize().x * mPipBoundsState.getBoundsScale()),
+                    (int) (mPipBoundsState.getMaxSize().y * mPipBoundsState.getBoundsScale()));
+
             // Calculate the PiP bounds in the new orientation based on same fraction along the
             // rotated movement bounds.
             final Rect postChangeMovementBounds = mPipBoundsAlgorithm.getMovementBounds(
@@ -822,6 +816,15 @@
                     mPipDisplayLayoutState.getDisplayBounds(),
                     mPipDisplayLayoutState.getDisplayLayout().stableInsets());
 
+            // make sure we user resize to the updated bounds to avoid animating to any outdated
+            // sizes from the previous layout upon double tap CUJ
+            mPipBoundsState.setHasUserResizedPip(true);
+            mTouchHandler.setUserResizeBounds(postChangeBounds);
+
+            final boolean densityDpiChanged =
+                    mPipDisplayLayoutState.getDisplayLayout().densityDpi() != 0
+                            && (mPipDisplayLayoutState.getDisplayLayout().densityDpi()
+                            != layout.densityDpi());
             if (densityDpiChanged) {
                 // Using PipMotionHelper#movePip directly here may cause race condition since
                 // the app content in PiP mode may or may not be updated for the new density dpi.
@@ -833,15 +836,6 @@
                 // Directly move PiP to its final destination bounds without animation.
                 mPipTaskOrganizer.scheduleFinishResizePip(postChangeBounds);
             }
-
-            // if the pip window size is beyond allowed bounds user resize to normal bounds
-            if (mPipBoundsState.getBounds().width() < mPipBoundsState.getMinSize().x
-                    || mPipBoundsState.getBounds().width() > mPipBoundsState.getMaxSize().x
-                    || mPipBoundsState.getBounds().height() < mPipBoundsState.getMinSize().y
-                    || mPipBoundsState.getBounds().height() > mPipBoundsState.getMaxSize().y) {
-                mTouchHandler.userResizeTo(mPipBoundsState.getNormalBounds(), snapFraction);
-            }
-
         } else {
             updateDisplayLayout.run();
         }
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 e5f9fdc..f175775 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
@@ -15,7 +15,6 @@
  */
 package com.android.wm.shell.pip.phone;
 
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_PINCH_RESIZE;
 import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
 import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT;
 import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE;
@@ -31,7 +30,6 @@
 import android.graphics.Region;
 import android.hardware.input.InputManager;
 import android.os.Looper;
-import android.provider.DeviceConfig;
 import android.view.BatchedInputEventReceiver;
 import android.view.Choreographer;
 import android.view.InputChannel;
@@ -155,21 +153,8 @@
         mContext.getDisplay().getRealSize(mMaxSize);
         reloadResources();
 
-        mEnablePinchResize = DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                PIP_PINCH_RESIZE,
-                /* defaultValue = */ true);
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
-                mMainExecutor,
-                new DeviceConfig.OnPropertiesChangedListener() {
-                    @Override
-                    public void onPropertiesChanged(DeviceConfig.Properties properties) {
-                        if (properties.getKeyset().contains(PIP_PINCH_RESIZE)) {
-                            mEnablePinchResize = properties.getBoolean(
-                                    PIP_PINCH_RESIZE, /* defaultValue = */ true);
-                        }
-                    }
-                });
+        final Resources res = mContext.getResources();
+        mEnablePinchResize = res.getBoolean(R.bool.config_pipEnablePinchResize);
     }
 
     public void onConfigurationChanged() {
@@ -579,6 +564,12 @@
                     resizeRectAboutCenter(mLastResizeBounds, mMaxSize.x, mMaxSize.y);
                 }
 
+                // If user resize is smaller than min size, auto resize to min
+                if (mLastResizeBounds.width() < mMinSize.x
+                        || mLastResizeBounds.height() < mMinSize.y) {
+                    resizeRectAboutCenter(mLastResizeBounds, mMinSize.x, mMinSize.y);
+                }
+
                 // get the current movement bounds
                 final Rect movementBounds = mPipBoundsAlgorithm
                         .getMovementBounds(mLastResizeBounds);
@@ -679,6 +670,8 @@
         pw.println(innerPrefix + "mEnablePinchResize=" + mEnablePinchResize);
         pw.println(innerPrefix + "mThresholdCrossed=" + mThresholdCrossed);
         pw.println(innerPrefix + "mOhmOffset=" + mOhmOffset);
+        pw.println(innerPrefix + "mMinSize=" + mMinSize);
+        pw.println(innerPrefix + "mMaxSize=" + mMaxSize);
     }
 
     class PipResizeInputEventReceiver extends BatchedInputEventReceiver {
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 2ce4fb9..452a416 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
@@ -779,13 +779,10 @@
     }
 
     /**
-     * Resizes the pip window and updates user resized bounds
-     *
-     * @param bounds target bounds to resize to
-     * @param snapFraction snap fraction to apply after resizing
+     * Sets the user resize bounds tracked by {@link PipResizeGestureHandler}
      */
-    void userResizeTo(Rect bounds, float snapFraction) {
-        mPipResizeGestureHandler.userResizeTo(bounds, snapFraction);
+    void setUserResizeBounds(Rect bounds) {
+        mPipResizeGestureHandler.setUserResizeBounds(bounds);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java
deleted file mode 100644
index b8e4c04..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2023 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.pip2;
-
-import android.annotation.NonNull;
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.window.TransitionInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.Nullable;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
-import com.android.wm.shell.common.pip.PipBoundsState;
-import com.android.wm.shell.common.pip.PipUtils;
-import com.android.wm.shell.pip.PipMenuController;
-import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
-
-/** Placeholder, for demonstrate purpose only. */
-public class PipTransition extends PipTransitionController {
-    public PipTransition(
-            @NonNull ShellInit shellInit,
-            @NonNull ShellTaskOrganizer shellTaskOrganizer,
-            @NonNull Transitions transitions,
-            PipBoundsState pipBoundsState,
-            PipMenuController pipMenuController,
-            PipBoundsAlgorithm pipBoundsAlgorithm) {
-        super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController,
-                pipBoundsAlgorithm);
-    }
-
-    @Override
-    protected void onInit() {
-        if (PipUtils.isPip2ExperimentEnabled()) {
-            mTransitions.addHandler(this);
-        }
-    }
-
-    @Nullable
-    @Override
-    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
-            @NonNull TransitionRequestInfo request) {
-        return null;
-    }
-
-    @Override
-    public boolean startAnimation(@NonNull IBinder transition,
-            @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction startTransaction,
-            @NonNull SurfaceControl.Transaction finishTransaction,
-            @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        return false;
-    }
-
-    @Override
-    public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
-            @NonNull Transitions.TransitionFinishCallback finishCallback) {}
-
-    @Override
-    public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
-            @Nullable SurfaceControl.Transaction finishT) {}
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
new file mode 100644
index 0000000..d704b09
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2023 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.pip2.phone;
+
+import static android.view.WindowManager.TRANSIT_OPEN;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.PictureInPictureParams;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.pip.PipMenuController;
+import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.Transitions;
+
+/**
+ * Implementation of transitions for PiP on phone.
+ */
+public class PipTransition extends PipTransitionController {
+    @Nullable
+    private IBinder mAutoEnterButtonNavTransition;
+
+    public PipTransition(
+            @NonNull ShellInit shellInit,
+            @NonNull ShellTaskOrganizer shellTaskOrganizer,
+            @NonNull Transitions transitions,
+            PipBoundsState pipBoundsState,
+            PipMenuController pipMenuController,
+            PipBoundsAlgorithm pipBoundsAlgorithm) {
+        super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController,
+                pipBoundsAlgorithm);
+    }
+
+    @Override
+    protected void onInit() {
+        if (PipUtils.isPip2ExperimentEnabled()) {
+            mTransitions.addHandler(this);
+        }
+    }
+
+    @Nullable
+    @Override
+    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+            @NonNull TransitionRequestInfo request) {
+        if (isAutoEnterInButtonNavigation(request)) {
+            mAutoEnterButtonNavTransition = transition;
+            return getEnterPipTransaction(transition, request);
+        }
+        return null;
+    }
+
+    @Override
+    public void augmentRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request,
+            @NonNull WindowContainerTransaction outWct) {
+        if (isAutoEnterInButtonNavigation(request)) {
+            outWct.merge(getEnterPipTransaction(transition, request), true /* transfer */);
+            mAutoEnterButtonNavTransition = transition;
+        }
+    }
+
+    private WindowContainerTransaction getEnterPipTransaction(@NonNull IBinder transition,
+            @NonNull TransitionRequestInfo request) {
+        final ActivityManager.RunningTaskInfo pipTask = request.getPipTask();
+        PictureInPictureParams pipParams = pipTask.pictureInPictureParams;
+        mPipBoundsState.setBoundsStateForEntry(pipTask.topActivity, pipTask.topActivityInfo,
+                pipParams, mPipBoundsAlgorithm);
+
+        // calculate the entry bounds and notify core to move task to pinned with final bounds
+        final Rect entryBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.movePipActivityToPinnedRootTask(pipTask.token, entryBounds);
+        return wct;
+    }
+
+    private boolean isAutoEnterInButtonNavigation(@NonNull TransitionRequestInfo requestInfo) {
+        final ActivityManager.RunningTaskInfo pipTask = requestInfo.getPipTask();
+        if (pipTask == null) {
+            return false;
+        }
+        if (pipTask.pictureInPictureParams == null) {
+            return false;
+        }
+
+        // Assuming auto-enter is enabled and pipTask is non-null, the TRANSIT_OPEN request type
+        // implies that we are entering PiP in button navigation mode. This is guaranteed by
+        // TaskFragment#startPausing()` in Core which wouldn't get called in gesture nav.
+        return requestInfo.getType() == TRANSIT_OPEN
+                && pipTask.pictureInPictureParams.isAutoEnterEnabled();
+    }
+
+    @Override
+    public boolean startAnimation(@NonNull IBinder transition,
+            @NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        if (transition == mAutoEnterButtonNavTransition) {
+            startTransaction.apply();
+            finishCallback.onTransitionFinished(null);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {}
+
+    @Override
+    public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
+            @Nullable SurfaceControl.Transaction finishT) {}
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index ead2f9c..d31476c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -54,6 +54,7 @@
 import android.window.WindowContainerTransaction;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -279,7 +280,7 @@
             mDeathHandler = () -> {
                 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                         "[%d] RecentsController.DeathRecipient: binder died", mInstanceId);
-                finish(mWillFinishToHome, false /* leaveHint */);
+                finish(mWillFinishToHome, false /* leaveHint */, null /* finishCb */);
             };
             try {
                 mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */);
@@ -313,7 +314,7 @@
                 }
             }
             if (mFinishCB != null) {
-                finishInner(toHome, false /* userLeave */);
+                finishInner(toHome, false /* userLeave */, null /* finishCb */);
             } else {
                 cleanUp();
             }
@@ -670,7 +671,8 @@
                 // now and let it do its animation (since recents is going to be occluded).
                 sendCancelWithSnapshots();
                 mExecutor.executeDelayed(
-                        () -> finishInner(true /* toHome */, false /* userLeaveHint */), 0);
+                        () -> finishInner(true /* toHome */, false /* userLeaveHint */,
+                                null /* finishCb */), 0);
                 return;
             }
             if (recentsOpening != null) {
@@ -899,11 +901,12 @@
 
         @Override
         @SuppressLint("NewApi")
-        public void finish(boolean toHome, boolean sendUserLeaveHint) {
-            mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint));
+        public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) {
+            mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb));
         }
 
-        private void finishInner(boolean toHome, boolean sendUserLeaveHint) {
+        private void finishInner(boolean toHome, boolean sendUserLeaveHint,
+                IResultReceiver runnerFinishCb) {
             if (mFinishCB == null) {
                 Slog.e(TAG, "Duplicate call to finish");
                 return;
@@ -993,6 +996,16 @@
             }
             cleanUp();
             finishCB.onTransitionFinished(wct.isEmpty() ? null : wct);
+            if (runnerFinishCb != null) {
+                try {
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                            "[%d] RecentsController.finishInner: calling finish callback",
+                            mInstanceId);
+                    runnerFinishCb.send(0, null);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to report transition finished", e);
+                }
+            }
         }
 
         @Override
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 5e2c61b..68ca231 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
@@ -143,6 +143,8 @@
 import com.android.wm.shell.util.TransitionUtil;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -2240,6 +2242,25 @@
         return SPLIT_POSITION_UNDEFINED;
     }
 
+    /**
+     * Returns the {@link StageType} where {@param token} is being used
+     * {@link SplitScreen#STAGE_TYPE_UNDEFINED} otherwise
+     */
+    @StageType
+    public int getSplitItemStage(@Nullable WindowContainerToken token) {
+        if (token == null) {
+            return STAGE_TYPE_UNDEFINED;
+        }
+
+        if (mMainStage.containsToken(token)) {
+            return STAGE_TYPE_MAIN;
+        } else if (mSideStage.containsToken(token)) {
+            return STAGE_TYPE_SIDE;
+        }
+
+        return STAGE_TYPE_UNDEFINED;
+    }
+
     @Override
     public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) {
         final StageTaskListener topLeftStage =
@@ -2477,7 +2498,16 @@
                 mRecentTasks.ifPresent(
                         recentTasks -> recentTasks.removeSplitPair(triggerTask.taskId));
             }
-            prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, outWCT);
+            @StageType int topStage = STAGE_TYPE_UNDEFINED;
+            if (isSplitScreenVisible()) {
+                // Get the stage where a child exists to keep that stage onTop
+                if (mMainStage.getChildCount() != 0 && mSideStage.getChildCount() == 0) {
+                    topStage = STAGE_TYPE_MAIN;
+                } else if (mSideStage.getChildCount() != 0 && mMainStage.getChildCount() == 0) {
+                    topStage = STAGE_TYPE_SIDE;
+                }
+            }
+            prepareExitSplitScreen(topStage, outWCT);
         }
     }
 
@@ -2691,7 +2721,7 @@
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         boolean shouldAnimate = true;
         if (mSplitTransitions.isPendingEnter(transition)) {
-            shouldAnimate = startPendingEnterAnimation(
+            shouldAnimate = startPendingEnterAnimation(transition,
                     mSplitTransitions.mPendingEnter, info, startTransaction, finishTransaction);
         } else if (mSplitTransitions.isPendingDismiss(transition)) {
             final SplitScreenTransitions.DismissSession dismiss = mSplitTransitions.mPendingDismiss;
@@ -2730,7 +2760,7 @@
         }
     }
 
-    private boolean startPendingEnterAnimation(
+    private boolean startPendingEnterAnimation(@NonNull IBinder transition,
             @NonNull SplitScreenTransitions.EnterSession enterTransition,
             @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
             @NonNull SurfaceControl.Transaction finishT) {
@@ -2759,21 +2789,22 @@
             }
         }
 
-        if (mSplitTransitions.mPendingEnter.mExtraTransitType
+        SplitScreenTransitions.EnterSession pendingEnter = mSplitTransitions.mPendingEnter;
+        if (pendingEnter.mExtraTransitType
                 == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
             // Open to side should only be used when split already active and foregorund.
             if (mainChild == null && sideChild == null) {
                 Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
                         "Launched a task in split, but didn't receive any task in transition."));
                 // This should happen when the target app is already on front, so just cancel.
-                mSplitTransitions.mPendingEnter.cancel(null);
+                pendingEnter.cancel(null);
                 return true;
             }
         } else {
             if (mainChild == null || sideChild == null) {
                 final int dismissTop = mainChild != null ? STAGE_TYPE_MAIN :
                         (sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED);
-                mSplitTransitions.mPendingEnter.cancel(
+                pendingEnter.cancel(
                         (cancelWct, cancelT) -> prepareExitSplitScreen(dismissTop, cancelWct));
                 Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
                         "launched 2 tasks in split, but didn't receive "
@@ -2784,6 +2815,12 @@
                 if (mRecentTasks.isPresent() && sideChild != null) {
                     mRecentTasks.get().removeSplitPair(sideChild.getTaskInfo().taskId);
                 }
+                if (pendingEnter.mRemoteHandler != null) {
+                    // Pass false for aborted since WM didn't abort, business logic chose to
+                    // terminate/exit early
+                    pendingEnter.mRemoteHandler.onTransitionConsumed(transition,
+                            false /*aborted*/, finishT);
+                }
                 mSplitUnsupportedToast.show();
                 return true;
             }
@@ -2894,7 +2931,11 @@
         return SPLIT_POSITION_UNDEFINED;
     }
 
-    /** Synchronize split-screen state with transition and make appropriate preparations. */
+    /**
+     * Synchronize split-screen state with transition and make appropriate preparations.
+     * @param toStage The stage that will not be dismissed. If set to
+     *        {@link SplitScreen#STAGE_TYPE_UNDEFINED} then both stages will be dismissed
+     */
     public void prepareDismissAnimation(@StageType int toStage, @ExitReason int dismissReason,
             @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
             @NonNull SurfaceControl.Transaction finishT) {
@@ -3109,6 +3150,7 @@
                 null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
     }
 
+    @NeverCompile
     @Override
     public void dump(@NonNull PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 83dc7fa..226fe08 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+
 import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
@@ -49,6 +50,7 @@
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.recents.RecentsTransitionHandler;
+import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.splitscreen.StageCoordinator;
 import com.android.wm.shell.sysui.ShellInit;
@@ -510,8 +512,26 @@
             // make a new startTransaction because pip's startEnterAnimation "consumes" it so
             // we need a separate one to send over to launcher.
             SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction();
+            @SplitScreen.StageType int topStageToKeep = STAGE_TYPE_UNDEFINED;
+            if (mSplitHandler.isSplitScreenVisible()) {
+                // The non-going home case, we could be pip-ing one of the split stages and keep
+                // showing the other
+                for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+                    TransitionInfo.Change change = info.getChanges().get(i);
+                    if (change == pipChange) {
+                        // Ignore the change/task that's going into Pip
+                        continue;
+                    }
+                    @SplitScreen.StageType int splitItemStage =
+                            mSplitHandler.getSplitItemStage(change.getLastParent());
+                    if (splitItemStage != STAGE_TYPE_UNDEFINED) {
+                        topStageToKeep = splitItemStage;
+                        break;
+                    }
+                }
+            }
             // Let split update internal state for dismiss.
-            mSplitHandler.prepareDismissAnimation(STAGE_TYPE_UNDEFINED,
+            mSplitHandler.prepareDismissAnimation(topStageToKeep,
                     EXIT_REASON_CHILD_TASK_ENTER_PIP, everythingElse, otherStartT,
                     finishTransaction);
 
@@ -693,9 +713,19 @@
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        Transitions.TransitionFinishCallback finishCB = wct -> {
+            mixed.mInFlightSubAnimations--;
+            if (mixed.mInFlightSubAnimations == 0) {
+                mActiveTransitions.remove(mixed);
+                finishCallback.onTransitionFinished(wct);
+            }
+        };
+
+        mixed.mInFlightSubAnimations++;
         boolean consumed = mRecentsHandler.startAnimation(
-                mixed.mTransition, info, startTransaction, finishTransaction, finishCallback);
+                mixed.mTransition, info, startTransaction, finishTransaction, finishCB);
         if (!consumed) {
+            mixed.mInFlightSubAnimations--;
             return false;
         }
         if (mDesktopTasksController != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index e0635ac..de03f58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -322,7 +322,6 @@
         final Runnable onAnimFinish = () -> {
             if (!animations.isEmpty()) return;
             mAnimations.remove(transition);
-            info.releaseAllSurfaces();
             finishCallback.onTransitionFinished(null /* wct */);
         };
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index fab2dd2..8b050e5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -152,6 +152,16 @@
     }
 
     @Override
+    public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
+            @Nullable SurfaceControl.Transaction finishTransaction) {
+        try {
+            mRemote.getRemoteTransition().onTransitionConsumed(transition, aborted);
+        } catch (RemoteException e) {
+            Log.e(Transitions.TAG, "Error calling onTransitionConsumed()", e);
+        }
+    }
+
+    @Override
     public String toString() {
         return "OneShotRemoteHandler:" + mRemote.getDebugName() + ":"
                 + mRemote.getRemoteTransition();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index a90edf2..592b22a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -86,7 +86,16 @@
     @Override
     public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
             @Nullable SurfaceControl.Transaction finishT) {
-        mRequestedRemotes.remove(transition);
+        RemoteTransition remoteTransition = mRequestedRemotes.remove(transition);
+        if (remoteTransition == null) {
+            return;
+        }
+
+        try {
+            remoteTransition.getRemoteTransition().onTransitionConsumed(transition, aborted);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error delegating onTransitionConsumed()", e);
+        }
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index c74b3f3..0d9a9e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -277,7 +277,7 @@
             @NonNull ShellExecutor animExecutor) {
         this(context, shellInit, shellController, organizer, pool, displayController, mainExecutor,
                 mainHandler, animExecutor, null,
-                new RootTaskDisplayAreaOrganizer(mainExecutor, context));
+                new RootTaskDisplayAreaOrganizer(mainExecutor, context, shellInit));
     }
 
     public Transitions(@NonNull Context context,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 780bbb5..bf99ab3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -376,7 +376,7 @@
         public void onClick(View v) {
             final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
             final int id = v.getId();
-            if (id == R.id.close_window || id == R.id.close_button) {
+            if (id == R.id.close_window) {
                 mTaskOperations.closeTask(mTaskToken);
                 if (isTaskInSplitScreen(mTaskId)) {
                     RunningTaskInfo remainingTask = getOtherSplitTask(mTaskId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
index a7a11de..15f8f1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
@@ -42,7 +42,6 @@
 import android.window.SurfaceSyncGroup;
 
 import com.android.wm.shell.R;
-import com.android.wm.shell.desktopmode.DesktopModeStatus;
 
 /**
  * Handle menu opened when the appropriate button is clicked on.
@@ -56,12 +55,8 @@
     private static final String TAG = "HandleMenu";
     private final Context mContext;
     private final WindowDecoration mParentDecor;
-    private WindowDecoration.AdditionalWindow mAppInfoPill;
-    private WindowDecoration.AdditionalWindow mWindowingPill;
-    private WindowDecoration.AdditionalWindow mMoreActionsPill;
-    private final PointF mAppInfoPillPosition = new PointF();
-    private final PointF mWindowingPillPosition = new PointF();
-    private final PointF mMoreActionsPillPosition = new PointF();
+    private WindowDecoration.AdditionalWindow mHandleMenuWindow;
+    private final PointF mHandleMenuPosition = new PointF();
     private final boolean mShouldShowWindowingPill;
     private final Drawable mAppIcon;
     private final CharSequence mAppName;
@@ -73,13 +68,8 @@
     private final int mCaptionY;
     private int mMarginMenuTop;
     private int mMarginMenuStart;
-    private int mMarginMenuSpacing;
+    private int mMenuHeight;
     private int mMenuWidth;
-    private int mAppInfoPillHeight;
-    private int mWindowingPillHeight;
-    private int mMoreActionsPillHeight;
-    private int mShadowRadius;
-    private int mCornerRadius;
 
 
     HandleMenu(WindowDecoration parentDecor, int layoutResId, int captionX, int captionY,
@@ -104,102 +94,86 @@
         final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG);
         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
 
-        createAppInfoPill(t, ssg);
-        if (mShouldShowWindowingPill) {
-            createWindowingPill(t, ssg);
-        }
-        createMoreActionsPill(t, ssg);
+        createHandleMenuWindow(t, ssg);
         ssg.addTransaction(t);
         ssg.markSyncReady();
         setupHandleMenu();
     }
 
-    private void createAppInfoPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
-        final int x = (int) mAppInfoPillPosition.x;
-        final int y = (int) mAppInfoPillPosition.y;
-        mAppInfoPill = mParentDecor.addWindow(
-                R.layout.desktop_mode_window_decor_handle_menu_app_info_pill,
-                "Menu's app info pill",
-                t, ssg, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius);
-    }
-
-    private void createWindowingPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
-        final int x = (int) mWindowingPillPosition.x;
-        final int y = (int) mWindowingPillPosition.y;
-        mWindowingPill = mParentDecor.addWindow(
-                R.layout.desktop_mode_window_decor_handle_menu_windowing_pill,
-                "Menu's windowing pill",
-                t, ssg, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius);
-    }
-
-    private void createMoreActionsPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
-        final int x = (int) mMoreActionsPillPosition.x;
-        final int y = (int) mMoreActionsPillPosition.y;
-        mMoreActionsPill = mParentDecor.addWindow(
-                R.layout.desktop_mode_window_decor_handle_menu_more_actions_pill,
-                "Menu's more actions pill",
-                t, ssg, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius);
+    private void createHandleMenuWindow(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
+        final int x = (int) mHandleMenuPosition.x;
+        final int y = (int) mHandleMenuPosition.y;
+        mHandleMenuWindow = mParentDecor.addWindow(
+                R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu",
+                t, ssg, x, y, mMenuWidth, mMenuHeight);
     }
 
     /**
-     * Set up interactive elements and color of this handle menu
+     * Set up all three pills of the handle menu: app info pill, windowing pill, & more actions
+     * pill.
      */
     private void setupHandleMenu() {
-        // App Info pill setup.
-        final View appInfoPillView = mAppInfoPill.mWindowViewHost.getView();
-        final ImageButton collapseBtn = appInfoPillView.findViewById(R.id.collapse_menu_button);
-        final ImageView appIcon = appInfoPillView.findViewById(R.id.application_icon);
-        final TextView appName = appInfoPillView.findViewById(R.id.application_name);
+        final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView();
+        handleMenu.setOnTouchListener(mOnTouchListener);
+        setupAppInfoPill(handleMenu);
+        if (mShouldShowWindowingPill) {
+            setupWindowingPill(handleMenu);
+        }
+        setupMoreActionsPill(handleMenu);
+    }
+
+    /**
+     * Set up interactive elements of handle menu's app info pill.
+     */
+    private void setupAppInfoPill(View handleMenu) {
+        final ImageButton collapseBtn = handleMenu.findViewById(R.id.collapse_menu_button);
+        final ImageView appIcon = handleMenu.findViewById(R.id.application_icon);
+        final TextView appName = handleMenu.findViewById(R.id.application_name);
         collapseBtn.setOnClickListener(mOnClickListener);
-        appInfoPillView.setOnTouchListener(mOnTouchListener);
         appIcon.setImageDrawable(mAppIcon);
         appName.setText(mAppName);
+    }
 
-        // Windowing pill setup.
-        if (mShouldShowWindowingPill) {
-            final View windowingPillView = mWindowingPill.mWindowViewHost.getView();
-            final ImageButton fullscreenBtn = windowingPillView.findViewById(
-                    R.id.fullscreen_button);
-            final ImageButton splitscreenBtn = windowingPillView.findViewById(
-                    R.id.split_screen_button);
-            final ImageButton floatingBtn = windowingPillView.findViewById(R.id.floating_button);
-            // TODO: Remove once implemented.
-            floatingBtn.setVisibility(View.GONE);
+    /**
+     * Set up interactive elements and color of handle menu's windowing pill.
+     */
+    private void setupWindowingPill(View handleMenu) {
+        final ImageButton fullscreenBtn = handleMenu.findViewById(
+                R.id.fullscreen_button);
+        final ImageButton splitscreenBtn = handleMenu.findViewById(
+                R.id.split_screen_button);
+        final ImageButton floatingBtn = handleMenu.findViewById(R.id.floating_button);
+        // TODO: Remove once implemented.
+        floatingBtn.setVisibility(View.GONE);
 
-            final ImageButton desktopBtn = windowingPillView.findViewById(R.id.desktop_button);
-            fullscreenBtn.setOnClickListener(mOnClickListener);
-            splitscreenBtn.setOnClickListener(mOnClickListener);
-            floatingBtn.setOnClickListener(mOnClickListener);
-            desktopBtn.setOnClickListener(mOnClickListener);
-            // The button corresponding to the windowing mode that the task is currently in uses a
-            // different color than the others.
-            final int[] iconColors = getWindowingIconColor();
-            final ColorStateList inActiveColorStateList = ColorStateList.valueOf(iconColors[0]);
-            final ColorStateList activeColorStateList = ColorStateList.valueOf(iconColors[1]);
-            fullscreenBtn.setImageTintList(
-                    mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
-                            ? activeColorStateList : inActiveColorStateList);
-            splitscreenBtn.setImageTintList(
-                    mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
-                            ? activeColorStateList : inActiveColorStateList);
-            floatingBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_PINNED
-                    ? activeColorStateList : inActiveColorStateList);
-            desktopBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
-                    ? activeColorStateList : inActiveColorStateList);
-        }
+        final ImageButton desktopBtn = handleMenu.findViewById(R.id.desktop_button);
+        fullscreenBtn.setOnClickListener(mOnClickListener);
+        splitscreenBtn.setOnClickListener(mOnClickListener);
+        floatingBtn.setOnClickListener(mOnClickListener);
+        desktopBtn.setOnClickListener(mOnClickListener);
+        // The button corresponding to the windowing mode that the task is currently in uses a
+        // different color than the others.
+        final ColorStateList[] iconColors = getWindowingIconColor();
+        final ColorStateList inActiveColorStateList = iconColors[0];
+        final ColorStateList activeColorStateList = iconColors[1];
+        final int windowingMode = mTaskInfo.getWindowingMode();
+        fullscreenBtn.setImageTintList(windowingMode == WINDOWING_MODE_FULLSCREEN
+                        ? activeColorStateList : inActiveColorStateList);
+        splitscreenBtn.setImageTintList(windowingMode == WINDOWING_MODE_MULTI_WINDOW
+                        ? activeColorStateList : inActiveColorStateList);
+        floatingBtn.setImageTintList(windowingMode == WINDOWING_MODE_PINNED
+                ? activeColorStateList : inActiveColorStateList);
+        desktopBtn.setImageTintList(windowingMode == WINDOWING_MODE_FREEFORM
+                ? activeColorStateList : inActiveColorStateList);
+    }
 
-        // More Actions pill setup.
-        final View moreActionsPillView = mMoreActionsPill.mWindowViewHost.getView();
-        final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button);
-        if (shouldShowCloseButton()) {
-            closeBtn.setVisibility(View.GONE);
-        } else {
-            closeBtn.setVisibility(View.VISIBLE);
-            closeBtn.setOnClickListener(mOnClickListener);
-        }
-        final Button selectBtn = moreActionsPillView.findViewById(R.id.select_button);
+    /**
+     * Set up interactive elements & height of handle menu's more actions pill
+     */
+    private void setupMoreActionsPill(View handleMenu) {
+        final Button selectBtn = handleMenu.findViewById(R.id.select_button);
         selectBtn.setOnClickListener(mOnClickListener);
-        final Button screenshotBtn = moreActionsPillView.findViewById(R.id.screenshot_button);
+        final Button screenshotBtn = handleMenu.findViewById(R.id.screenshot_button);
         // TODO: Remove once implemented.
         screenshotBtn.setVisibility(View.GONE);
     }
@@ -208,7 +182,7 @@
      * Returns array of windowing icon color based on current UI theme. First element of the
      * array is for inactive icons and the second is for active icons.
      */
-    private int[] getWindowingIconColor() {
+    private ColorStateList[] getWindowingIconColor() {
         final int mode = mContext.getResources().getConfiguration().uiMode
                 & Configuration.UI_MODE_NIGHT_MASK;
         final boolean isNightMode = (mode == Configuration.UI_MODE_NIGHT_YES);
@@ -218,11 +192,12 @@
         final int inActiveColor = typedArray.getColor(0, isNightMode ? Color.WHITE : Color.BLACK);
         final int activeColor = typedArray.getColor(1, isNightMode ? Color.WHITE : Color.BLACK);
         typedArray.recycle();
-        return new int[] {inActiveColor, activeColor};
+        return new ColorStateList[]{ColorStateList.valueOf(inActiveColor),
+                ColorStateList.valueOf(activeColor)};
     }
 
     /**
-     * Updates the handle menu pills' position variables to reflect their next positions
+     * Updates handle menu's position variables to reflect its next position.
      */
     private void updateHandleMenuPillPositions() {
         final int menuX, menuY;
@@ -239,39 +214,19 @@
             menuY = mCaptionY + mMarginMenuStart;
         }
 
-        // App Info pill setup.
-        final int appInfoPillY = menuY;
-        mAppInfoPillPosition.set(menuX, appInfoPillY);
+        // Handle Menu position setup.
+        mHandleMenuPosition.set(menuX, menuY);
 
-        final int windowingPillY, moreActionsPillY;
-        if (mShouldShowWindowingPill) {
-            windowingPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing;
-            mWindowingPillPosition.set(menuX, windowingPillY);
-            moreActionsPillY = windowingPillY + mWindowingPillHeight + mMarginMenuSpacing;
-            mMoreActionsPillPosition.set(menuX, moreActionsPillY);
-        } else {
-            // Just start after the end of the app info pill + margins.
-            moreActionsPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing;
-            mMoreActionsPillPosition.set(menuX, moreActionsPillY);
-        }
     }
 
     /**
      * Update pill layout, in case task changes have caused positioning to change.
      */
     void relayout(SurfaceControl.Transaction t) {
-        if (mAppInfoPill != null) {
+        if (mHandleMenuWindow != null) {
             updateHandleMenuPillPositions();
-            t.setPosition(mAppInfoPill.mWindowSurface,
-                    mAppInfoPillPosition.x, mAppInfoPillPosition.y);
-            // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
-            final boolean shouldShowWindowingPill = DesktopModeStatus.isEnabled();
-            if (shouldShowWindowingPill) {
-                t.setPosition(mWindowingPill.mWindowSurface,
-                        mWindowingPillPosition.x, mWindowingPillPosition.y);
-            }
-            t.setPosition(mMoreActionsPill.mWindowSurface,
-                    mMoreActionsPillPosition.x, mMoreActionsPillPosition.y);
+            t.setPosition(mHandleMenuWindow.mWindowSurface,
+                    mHandleMenuPosition.x, mHandleMenuPosition.y);
         }
     }
 
@@ -283,12 +238,12 @@
      * @param ev the MotionEvent to compare against.
      */
     void checkClickEvent(MotionEvent ev) {
-        final View appInfoPill = mAppInfoPill.mWindowViewHost.getView();
-        final ImageButton collapse = appInfoPill.findViewById(R.id.collapse_menu_button);
+        final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView();
+        final ImageButton collapse = handleMenu.findViewById(R.id.collapse_menu_button);
         // Translate the input point from display coordinates to the same space as the collapse
         // button, meaning its parent (app info pill view).
-        final PointF inputPoint = new PointF(ev.getX() - mAppInfoPillPosition.x,
-                ev.getY() - mAppInfoPillPosition.y);
+        final PointF inputPoint = new PointF(ev.getX() - mHandleMenuPosition.x,
+                ev.getY() - mHandleMenuPosition.y);
         if (pointInView(collapse, inputPoint.x, inputPoint.y)) {
             mOnClickListener.onClick(collapse);
         }
@@ -303,23 +258,10 @@
      */
     boolean isValidMenuInput(PointF inputPoint) {
         if (!viewsLaidOut()) return true;
-        final boolean pointInAppInfoPill = pointInView(
-                mAppInfoPill.mWindowViewHost.getView(),
-                inputPoint.x - mAppInfoPillPosition.x,
-                inputPoint.y - mAppInfoPillPosition.y);
-        boolean pointInWindowingPill = false;
-        if (mWindowingPill != null) {
-            pointInWindowingPill = pointInView(
-                    mWindowingPill.mWindowViewHost.getView(),
-                    inputPoint.x - mWindowingPillPosition.x,
-                    inputPoint.y - mWindowingPillPosition.y);
-        }
-        final boolean pointInMoreActionsPill = pointInView(
-                mMoreActionsPill.mWindowViewHost.getView(),
-                inputPoint.x - mMoreActionsPillPosition.x,
-                inputPoint.y - mMoreActionsPillPosition.y);
-
-        return pointInAppInfoPill || pointInWindowingPill || pointInMoreActionsPill;
+        return pointInView(
+                mHandleMenuWindow.mWindowViewHost.getView(),
+                inputPoint.x - mHandleMenuPosition.x,
+                inputPoint.y - mHandleMenuPosition.y);
     }
 
     private boolean pointInView(View v, float x, float y) {
@@ -331,33 +273,31 @@
      * Check if the views for handle menu can be seen.
      */
     private boolean viewsLaidOut() {
-        return mAppInfoPill.mWindowViewHost.getView().isLaidOut();
+        return mHandleMenuWindow.mWindowViewHost.getView().isLaidOut();
     }
 
-
     private void loadHandleMenuDimensions() {
         final Resources resources = mContext.getResources();
         mMenuWidth = loadDimensionPixelSize(resources,
                 R.dimen.desktop_mode_handle_menu_width);
+        mMenuHeight = getHandleMenuHeight(resources);
         mMarginMenuTop = loadDimensionPixelSize(resources,
                 R.dimen.desktop_mode_handle_menu_margin_top);
         mMarginMenuStart = loadDimensionPixelSize(resources,
                 R.dimen.desktop_mode_handle_menu_margin_start);
-        mMarginMenuSpacing = loadDimensionPixelSize(resources,
-                R.dimen.desktop_mode_handle_menu_pill_spacing_margin);
-        mAppInfoPillHeight = loadDimensionPixelSize(resources,
-                R.dimen.desktop_mode_handle_menu_app_info_pill_height);
-        mWindowingPillHeight = loadDimensionPixelSize(resources,
-                R.dimen.desktop_mode_handle_menu_windowing_pill_height);
-        mMoreActionsPillHeight = shouldShowCloseButton()
-                ? loadDimensionPixelSize(resources,
-                        R.dimen.desktop_mode_handle_menu_more_actions_pill_freeform_height)
-                : loadDimensionPixelSize(resources,
-                        R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
-        mShadowRadius = loadDimensionPixelSize(resources,
-                R.dimen.desktop_mode_handle_menu_shadow_radius);
-        mCornerRadius = loadDimensionPixelSize(resources,
-                R.dimen.desktop_mode_handle_menu_corner_radius);
+    }
+
+    /**
+     * Determines handle menu height based on if windowing pill should be shown.
+     */
+    private int getHandleMenuHeight(Resources resources) {
+        int menuHeight = loadDimensionPixelSize(resources,
+                R.dimen.desktop_mode_handle_menu_height);
+        if (!mShouldShowWindowingPill) {
+            menuHeight -= loadDimensionPixelSize(resources,
+                    R.dimen.desktop_mode_handle_menu_windowing_pill_height);
+        }
+        return menuHeight;
     }
 
     private int loadDimensionPixelSize(Resources resources, int resourceId) {
@@ -367,19 +307,9 @@
         return resources.getDimensionPixelSize(resourceId);
     }
 
-    private boolean shouldShowCloseButton() {
-        return mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM;
-    }
-
     void close() {
-        mAppInfoPill.releaseView();
-        mAppInfoPill = null;
-        if (mWindowingPill != null) {
-            mWindowingPill.releaseView();
-            mWindowingPill = null;
-        }
-        mMoreActionsPill.releaseView();
-        mMoreActionsPill = null;
+        mHandleMenuWindow.releaseView();
+        mHandleMenuWindow = null;
     }
 
     static final class Builder {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
index 09fc3da..368231e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
@@ -132,6 +132,13 @@
                 t.setAlpha(mVeilSurface, mVeilAnimator.getAnimatedFraction());
                 t.apply();
             });
+            mVeilAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    t.setAlpha(mVeilSurface, 1);
+                    t.apply();
+                }
+            });
 
             final ValueAnimator iconAnimator = new ValueAnimator();
             iconAnimator.setFloatValues(0f, 1f);
@@ -192,8 +199,8 @@
      */
     public void updateResizeVeil(SurfaceControl.Transaction t, Rect newBounds) {
         if (mVeilAnimator != null && mVeilAnimator.isStarted()) {
-            // TODO(b/300145351): Investigate why ValueAnimator#end does not work here.
-            mVeilAnimator.setCurrentPlayTime(RESIZE_ALPHA_DURATION);
+            mVeilAnimator.removeAllUpdateListeners();
+            mVeilAnimator.end();
         }
         relayout(newBounds, t);
         mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 07fee43..335a588 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -44,6 +44,7 @@
 
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
 
 import java.util.function.Supplier;
 
@@ -283,10 +284,6 @@
 
         // Task surface itself
         float shadowRadius = loadDimension(resources, params.mShadowRadiusId);
-        int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
-        mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
-        mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
-        mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
         final Point taskPosition = mTaskInfo.positionInParent;
         if (isFullscreen) {
             // Setting the task crop to the width/height stops input events from being sent to
@@ -302,13 +299,22 @@
             finishT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
         }
         startT.setShadowRadius(mTaskSurface, shadowRadius)
-                .setColor(mTaskSurface, mTmpColor)
                 .show(mTaskSurface);
         finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
                 .setShadowRadius(mTaskSurface, shadowRadius);
         if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+            if (!DesktopModeStatus.isVeiledResizeEnabled()) {
+                // When fluid resize is enabled, add a background to freeform tasks
+                int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
+                mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
+                mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
+                mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
+                startT.setColor(mTaskSurface, mTmpColor);
+            }
             startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
             finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+        } else if (!DesktopModeStatus.isVeiledResizeEnabled()) {
+            startT.unsetColor(mTaskSurface);
         }
 
         if (mCaptionWindowManager == null) {
@@ -425,13 +431,10 @@
      * @param yPos         y position of new window
      * @param width        width of new window
      * @param height       height of new window
-     * @param shadowRadius radius of the shadow of the new window
-     * @param cornerRadius radius of the corners of the new window
      * @return the {@link AdditionalWindow} that was added.
      */
     AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t,
-            SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height, int shadowRadius,
-            int cornerRadius) {
+            SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) {
         final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
         SurfaceControl windowSurfaceControl = builder
                 .setName(namePrefix + " of Task=" + mTaskInfo.taskId)
@@ -442,8 +445,6 @@
 
         t.setPosition(windowSurfaceControl, xPos, yPos)
                 .setWindowCrop(windowSurfaceControl, width, height)
-                .setShadowRadius(windowSurfaceControl, shadowRadius)
-                .setCornerRadius(windowSurfaceControl, cornerRadius)
                 .show(windowSurfaceControl);
         final WindowManager.LayoutParams lp =
                 new WindowManager.LayoutParams(width, height,
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index 0058d11..7f02072 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -116,6 +116,7 @@
         "wm-flicker-common-assertions",
         "launcher-helper-lib",
         "launcher-aosp-tapl",
+        "com_android_wm_shell_flags_lib",
     ],
 }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
new file mode 100644
index 0000000..4f27ced
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 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.flicker.pip
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.Rotation
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import com.android.wm.shell.flicker.pip.common.PipTransition
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/** Test changing aspect ratio of pip. */
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipAspectRatioChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+    override val thisTransition: FlickerBuilder.() -> Unit = {
+        transitions {
+            pipApp.changeAspectRatio()
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun pipAspectRatioChangesProperly() {
+        flicker.assertLayersStart { this.visibleRegion(pipApp).isSameAspectRatio(16, 9) }
+        flicker.assertLayersEnd { this.visibleRegion(pipApp).isSameAspectRatio(1, 2) }
+    }
+
+    companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
+         */
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams() =
+            LegacyFlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(Rotation.ROTATION_0)
+            )
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 6748626..0fd1b2c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -18,6 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
+import android.tools.common.flicker.subject.exceptions.IncorrectRegionException
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.LegacyFlickerTest
@@ -40,14 +41,26 @@
         transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) }
     }
 
-    /** Checks that the visible region area of [pipApp] always decreases during the animation. */
+    /**
+     * Checks that the visible region area of [pipApp] decreases
+     * and then increases during the animation.
+     */
     @Presubmit
     @Test
-    fun pipLayerAreaDecreases() {
+    fun pipLayerAreaDecreasesThenIncreases() {
+        val isAreaDecreasing = arrayOf(true)
         flicker.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             pipLayerList.zipWithNext { previous, current ->
-                current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
+                if (isAreaDecreasing[0]) {
+                    try {
+                        current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
+                    } catch (e: IncorrectRegionException) {
+                        isAreaDecreasing[0] = false
+                    }
+                } else {
+                    previous.visibleRegion.notBiggerThan(current.visibleRegion.region)
+                }
             }
         }
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 54f9498..aadadd6 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -35,6 +35,7 @@
     static_libs: [
         "WindowManager-Shell",
         "junit",
+        "flag-junit-base",
         "androidx.test.runner",
         "androidx.test.rules",
         "androidx.test.ext.junit",
@@ -45,10 +46,11 @@
         "kotlinx-coroutines-core",
         "mockito-kotlin2",
         "mockito-target-extended-minus-junit4",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "platform-test-annotations",
         "servicestests-utils",
+        "com_android_wm_shell_flags_lib",
     ],
 
     libs: [
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
index 58d9a64..287a97c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
@@ -22,20 +22,24 @@
 import static android.view.View.LAYOUT_DIRECTION_RTL;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Insets;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableResources;
+import android.util.DisplayMetrics;
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.WindowMetrics;
@@ -257,6 +261,27 @@
         assertThat(mPositioner.hasUserModifiedDefaultPosition()).isTrue();
     }
 
+    @Test
+    public void testExpandedViewHeight_onLargeTablet() {
+        Insets insets = Insets.of(10, 20, 5, 15);
+        Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+        new WindowManagerConfig()
+                .setLargeScreen()
+                .setInsets(insets)
+                .setScreenBounds(screenBounds)
+                .setUpConfig();
+        mPositioner.update();
+
+        Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
+        Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
+
+        int manageButtonHeight =
+                mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height);
+        float expectedHeight = 1800 - 2 * 20 - manageButtonHeight;
+        assertThat(mPositioner.getExpandedViewHeight(bubble)).isWithin(0.1f).of(expectedHeight);
+    }
+
     /**
      * Calculates the Y position bubbles should be placed based on the config. Based on
      * the calculations in {@link BubblePositioner#getDefaultStartPosition()} and
@@ -323,6 +348,8 @@
                     ? MIN_WIDTH_FOR_TABLET
                     : MIN_WIDTH_FOR_TABLET - 1;
             mConfiguration.orientation = mOrientation;
+            mConfiguration.screenWidthDp = pxToDp(mScreenBounds.width());
+            mConfiguration.screenHeightDp = pxToDp(mScreenBounds.height());
 
             when(mConfiguration.getLayoutDirection()).thenReturn(mLayoutDirection);
             WindowInsets windowInsets = mock(WindowInsets.class);
@@ -331,5 +358,11 @@
             when(mWindowMetrics.getBounds()).thenReturn(mScreenBounds);
             when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
         }
+
+        private int pxToDp(float px) {
+            int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
+            float dp = px / ((float) dpi / DisplayMetrics.DENSITY_DEFAULT);
+            return (int) dp;
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index dea1617..ebcb640 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -54,6 +54,8 @@
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask
+import com.android.wm.shell.recents.RecentsTransitionHandler
+import com.android.wm.shell.recents.RecentsTransitionStateListener
 import com.android.wm.shell.splitscreen.SplitScreenController
 import com.android.wm.shell.sysui.ShellCommandHandler
 import com.android.wm.shell.sysui.ShellController
@@ -101,11 +103,13 @@
     @Mock lateinit var launchAdjacentController: LaunchAdjacentController
     @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration
     @Mock lateinit var splitScreenController: SplitScreenController
+    @Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler
 
     private lateinit var mockitoSession: StaticMockitoSession
     private lateinit var controller: DesktopTasksController
     private lateinit var shellInit: ShellInit
     private lateinit var desktopModeTaskRepository: DesktopModeTaskRepository
+    private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener
 
     private val shellExecutor = TestShellExecutor()
     // Mock running tasks are registered here so we can get the list from mock shell task organizer
@@ -126,6 +130,10 @@
         controller.splitScreenController = splitScreenController
 
         shellInit.init()
+
+        val captor = ArgumentCaptor.forClass(RecentsTransitionStateListener::class.java)
+        verify(recentsTransitionHandler).addTransitionStateListener(captor.capture())
+        recentsTransitionStateListener = captor.value
     }
 
     private fun createController(): DesktopTasksController {
@@ -144,6 +152,7 @@
             mToggleResizeDesktopTaskTransitionHandler,
             desktopModeTaskRepository,
             launchAdjacentController,
+            recentsTransitionHandler,
             shellExecutor
         )
     }
@@ -355,7 +364,7 @@
 
     @Test
     fun moveToDesktop_splitTaskExitsSplit() {
-        var task = setUpSplitScreenTask()
+        val task = setUpSplitScreenTask()
         controller.moveToDesktop(desktopModeWindowDecoration, task)
         val wct = getLatestMoveToDesktopWct()
         assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
@@ -367,7 +376,7 @@
 
     @Test
     fun moveToDesktop_fullscreenTaskDoesNotExitSplit() {
-        var task = setUpFullscreenTask()
+        val task = setUpFullscreenTask()
         controller.moveToDesktop(desktopModeWindowDecoration, task)
         val wct = getLatestMoveToDesktopWct()
         assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
@@ -666,6 +675,20 @@
     }
 
     @Test
+    fun handleRequest_recentsAnimationRunning_returnNull() {
+        // Set up a visible freeform task so a fullscreen task should be converted to freeform
+        val freeformTask = setUpFreeformTask()
+        markTaskVisible(freeformTask)
+
+        // Mark recents animation running
+        recentsTransitionStateListener.onAnimationStateChanged(true)
+
+        // Open a fullscreen task, check that it does not result in a WCT with changes to it
+        val fullscreenTask = createFullscreenTask()
+        assertThat(controller.handleRequest(Binder(), createTransition(fullscreenTask))).isNull()
+    }
+
+    @Test
     fun stashDesktopApps_stateUpdates() {
         whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true)
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index d34e27b..db98abb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.ComponentName;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -60,6 +61,9 @@
     /** The minimum possible size of the override min size's width or height */
     private static final int OVERRIDABLE_MIN_SIZE = 40;
 
+    /** The margin of error for floating point results. */
+    private static final float MARGIN_OF_ERROR = 0.05f;
+
     private PipBoundsState mPipBoundsState;
     private SizeSpecSource mSizeSpecSource;
     private ComponentName mTestComponentName1;
@@ -88,6 +92,27 @@
     }
 
     @Test
+    public void testBoundsScale() {
+        mPipBoundsState.setMaxSize(300, 300);
+        mPipBoundsState.setBounds(new Rect(0, 0, 100, 100));
+
+        final int currentWidth = mPipBoundsState.getBounds().width();
+        final Point maxSize = mPipBoundsState.getMaxSize();
+        final float expectedBoundsScale = Math.min((float) currentWidth / maxSize.x, 1.0f);
+
+        // test for currentWidth < maxWidth
+        assertEquals(expectedBoundsScale, mPipBoundsState.getBoundsScale(), MARGIN_OF_ERROR);
+
+        // reset the bounds to be at the maximum size spec
+        mPipBoundsState.setBounds(new Rect(0, 0, maxSize.x, maxSize.y));
+        assertEquals(1.0f, mPipBoundsState.getBoundsScale(), /* delta */ 0f);
+
+        // reset the bounds to be over the maximum size spec
+        mPipBoundsState.setBounds(new Rect(0, 0, maxSize.x * 2, maxSize.y * 2));
+        assertEquals(1.0f, mPipBoundsState.getBoundsScale(), /* delta */ 0f);
+    }
+
+    @Test
     public void testSetReentryState() {
         final Size size = new Size(100, 100);
         final float snapFraction = 0.5f;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index 6777a5b..9719ba8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -28,11 +28,13 @@
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.testing.TestableResources;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
@@ -98,6 +100,9 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        final TestableResources res = mContext.getOrCreateTestableResources();
+        res.addOverride(R.bool.config_pipEnablePinchResize, true);
+
         mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
         mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
         mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index ebc284b..befc702 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -208,6 +208,30 @@
 
     @Test
     @UiThreadTest
+    public void testRemoteTransitionConsumed() {
+        // Omit side child change
+        TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
+                .addChange(TRANSIT_OPEN, mMainChild)
+                .build();
+        TestRemoteTransition testRemote = new TestRemoteTransition();
+
+        IBinder transition = mSplitScreenTransitions.startEnterTransition(
+                TRANSIT_OPEN, new WindowContainerTransaction(),
+                new RemoteTransition(testRemote, "Test"), mStageCoordinator,
+                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
+        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
+        boolean accepted = mStageCoordinator.startAnimation(transition, info,
+                mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
+                mock(Transitions.TransitionFinishCallback.class));
+        assertTrue(accepted);
+
+        assertTrue(testRemote.isConsumed());
+
+    }
+
+    @Test
+    @UiThreadTest
     public void testMonitorInSplit() {
         enterSplit();
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index d598678..b9c9049 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -50,6 +50,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
@@ -92,6 +93,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.DisplayController;
@@ -145,7 +147,9 @@
         final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
                 mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
                 mMainHandler, mAnimExecutor);
-        verify(shellInit, times(1)).addInitCallback(any(), eq(t));
+        // One from Transitions, one from RootTaskDisplayAreaOrganizer
+        verify(shellInit).addInitCallback(any(), eq(t));
+        verify(shellInit).addInitCallback(any(), isA(RootTaskDisplayAreaOrganizer.class));
     }
 
     @Test
@@ -285,6 +289,10 @@
                     SurfaceControl.Transaction t, IBinder mergeTarget,
                     IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
             }
+
+            @Override
+            public void onTransitionConsumed(IBinder iBinder, boolean b) throws RemoteException {
+            }
         };
         IBinder transitToken = new Binder();
         transitions.requestStartTransition(transitToken,
@@ -427,6 +435,10 @@
                     SurfaceControl.Transaction t, IBinder mergeTarget,
                     IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
             }
+
+            @Override
+            public void onTransitionConsumed(IBinder iBinder, boolean b) throws RemoteException {
+            }
         };
 
         TransitionFilter filter = new TransitionFilter();
@@ -473,6 +485,10 @@
                     SurfaceControl.Transaction t, IBinder mergeTarget,
                     IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
             }
+
+            @Override
+            public void onTransitionConsumed(IBinder iBinder, boolean b) throws RemoteException {
+            }
         };
 
         final int transitType = TRANSIT_FIRST_CUSTOM + 1;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TestRemoteTransition.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TestRemoteTransition.java
index 39ab238..87330d2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TestRemoteTransition.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TestRemoteTransition.java
@@ -31,6 +31,7 @@
  */
 public class TestRemoteTransition extends IRemoteTransition.Stub {
     private boolean mCalled = false;
+    private boolean mConsumed = false;
     final WindowContainerTransaction mRemoteFinishWCT = new WindowContainerTransaction();
 
     @Override
@@ -48,6 +49,11 @@
             IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
     }
 
+    @Override
+    public void onTransitionConsumed(IBinder iBinder, boolean b) throws RemoteException {
+        mConsumed = true;
+    }
+
     /**
      * Check whether this remote transition
      * {@link #startAnimation(IBinder, TransitionInfo, SurfaceControl.Transaction,
@@ -56,4 +62,12 @@
     public boolean isCalled() {
         return mCalled;
     }
+
+    /**
+     * Check whether this remote transition's {@link #onTransitionConsumed(IBinder, boolean)}
+     * is called
+     */
+    public boolean isConsumed() {
+        return mConsumed;
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 76bc25a..fcb7863 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -17,7 +17,9 @@
 package com.android.wm.shell.windowdecor;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlBuilder;
 import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
 
@@ -36,6 +38,7 @@
 import static org.mockito.Mockito.same;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.mockito.quality.Strictness.LENIENT;
 
 import android.app.ActivityManager;
 import android.content.Context;
@@ -59,10 +62,12 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestRunningTaskInfoBuilder;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.tests.R;
 
 import org.junit.Before;
@@ -119,8 +124,6 @@
     private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams();
     private Configuration mWindowConfiguration = new Configuration();
     private int mCaptionMenuWidthId;
-    private int mCaptionMenuShadowRadiusId;
-    private int mCaptionMenuCornerRadiusId;
 
     @Before
     public void setUp() {
@@ -131,8 +134,6 @@
         mRelayoutParams.mLayoutResId = 0;
         mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
         mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width;
-        mCaptionMenuShadowRadiusId = R.dimen.test_caption_menu_shadow_radius;
-        mCaptionMenuCornerRadiusId = R.dimen.test_caption_menu_corner_radius;
         mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
         mRelayoutParams.mCornerRadius = CORNER_RADIUS;
 
@@ -205,12 +206,8 @@
                 createMockSurfaceControlBuilder(captionContainerSurface);
         mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
 
-        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
-                new ActivityManager.TaskDescription.Builder()
-                        .setBackgroundColor(Color.YELLOW);
         final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                 .setDisplayId(Display.DEFAULT_DISPLAY)
-                .setTaskDescriptionBuilder(taskDescriptionBuilder)
                 .setBounds(TASK_BOUNDS)
                 .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                 .setVisible(true)
@@ -259,8 +256,6 @@
         verify(mMockSurfaceControlFinishT).setCornerRadius(taskSurface, CORNER_RADIUS);
         verify(mMockSurfaceControlStartT)
                 .show(taskSurface);
-        verify(mMockSurfaceControlStartT)
-                .setColor(taskSurface, new float[] {1.f, 1.f, 0.f});
         verify(mMockSurfaceControlStartT).setShadowRadius(taskSurface, 10);
 
         assertEquals(300, mRelayoutResult.mWidth);
@@ -417,16 +412,6 @@
         final int height = WindowDecoration.loadDimensionPixelSize(
                 windowDecor.mDecorWindowContext.getResources(), mRelayoutParams.mCaptionHeightId);
         verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height);
-        final int shadowRadius = WindowDecoration.loadDimensionPixelSize(
-                windowDecor.mDecorWindowContext.getResources(),
-                mCaptionMenuShadowRadiusId);
-        verify(mMockSurfaceControlAddWindowT)
-                .setShadowRadius(additionalWindowSurface, shadowRadius);
-        final int cornerRadius = WindowDecoration.loadDimensionPixelSize(
-                windowDecor.mDecorWindowContext.getResources(),
-                mCaptionMenuCornerRadiusId);
-        verify(mMockSurfaceControlAddWindowT)
-                .setCornerRadius(additionalWindowSurface, cornerRadius);
         verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface);
         verify(mMockSurfaceControlViewHostFactory, Mockito.times(2))
                 .create(any(), eq(defaultDisplay), any());
@@ -516,6 +501,86 @@
         verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
     }
 
+    @Test
+    public void testRelayout_fluidResizeEnabled_freeformTask_setTaskSurfaceColor() {
+        StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
+                DesktopModeStatus.class).strictness(
+                LENIENT).startMocking();
+        when(DesktopModeStatus.isVeiledResizeEnabled()).thenReturn(false);
+
+        final Display defaultDisplay = mock(Display.class);
+        doReturn(defaultDisplay).when(mMockDisplayController)
+                .getDisplay(Display.DEFAULT_DISPLAY);
+
+        final SurfaceControl decorContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder decorContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(decorContainerSurface);
+        mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
+        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder captionContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(captionContainerSurface);
+        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
+
+        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+                new ActivityManager.TaskDescription.Builder()
+                        .setBackgroundColor(Color.YELLOW);
+
+        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+                .setDisplayId(Display.DEFAULT_DISPLAY)
+                .setTaskDescriptionBuilder(taskDescriptionBuilder)
+                .setVisible(true)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM)
+                .build();
+        taskInfo.isFocused = true;
+        final SurfaceControl taskSurface = mock(SurfaceControl.class);
+        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
+
+        windowDecor.relayout(taskInfo);
+
+        verify(mMockSurfaceControlStartT).setColor(taskSurface, new float[] {1.f, 1.f, 0.f});
+
+        mockitoSession.finishMocking();
+    }
+
+    @Test
+    public void testRelayout_fluidResizeEnabled_fullscreenTask_clearTaskSurfaceColor() {
+        StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
+                DesktopModeStatus.class).strictness(LENIENT).startMocking();
+        when(DesktopModeStatus.isVeiledResizeEnabled()).thenReturn(false);
+
+        final Display defaultDisplay = mock(Display.class);
+        doReturn(defaultDisplay).when(mMockDisplayController)
+                .getDisplay(Display.DEFAULT_DISPLAY);
+
+        final SurfaceControl decorContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder decorContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(decorContainerSurface);
+        mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
+        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder captionContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(captionContainerSurface);
+        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
+
+        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+                new ActivityManager.TaskDescription.Builder()
+                        .setBackgroundColor(Color.YELLOW);
+        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+                .setDisplayId(Display.DEFAULT_DISPLAY)
+                .setTaskDescriptionBuilder(taskDescriptionBuilder)
+                .setVisible(true)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                .build();
+        taskInfo.isFocused = true;
+        final SurfaceControl taskSurface = mock(SurfaceControl.class);
+        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
+
+        windowDecor.relayout(taskInfo);
+
+        verify(mMockSurfaceControlStartT).unsetColor(taskSurface);
+
+        mockitoSession.finishMocking();
+    }
+
     private TestWindowDecoration createWindowDecoration(
             ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
         return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
@@ -588,13 +653,11 @@
             int y = mRelayoutParams.mCaptionY;
             int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId);
             int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId);
-            int shadowRadius = loadDimensionPixelSize(resources, mCaptionMenuShadowRadiusId);
-            int cornerRadius = loadDimensionPixelSize(resources, mCaptionMenuCornerRadiusId);
             String name = "Test Window";
             WindowDecoration.AdditionalWindow additionalWindow =
-                    addWindow(R.layout.desktop_mode_window_decor_handle_menu_app_info_pill, name,
+                    addWindow(R.layout.desktop_mode_window_decor_handle_menu, name,
                             mMockSurfaceControlAddWindowT, mMockSurfaceSyncGroup, x, y,
-                            width, height, shadowRadius, cornerRadius);
+                            width, height);
             return additionalWindow;
         }
     }
diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp
index 64b53cb..4dafd0a 100644
--- a/libs/dream/lowlight/tests/Android.bp
+++ b/libs/dream/lowlight/tests/Android.bp
@@ -34,7 +34,7 @@
         "mockito-target-extended-minus-junit4",
         "platform-test-annotations",
         "testables",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS
index 6ca991d..bc17459 100644
--- a/libs/hwui/OWNERS
+++ b/libs/hwui/OWNERS
@@ -4,9 +4,8 @@
 djsollen@google.com
 jreck@google.com
 njawad@google.com
-reed@google.com
 scroggo@google.com
-stani@google.com
+sumir@google.com
 
 # For text, e.g. Typeface, Font, Minikin, etc.
 nona@google.com
diff --git a/libs/hwui/api/current.txt b/libs/hwui/api/current.txt
index c396a20..7940821 100644
--- a/libs/hwui/api/current.txt
+++ b/libs/hwui/api/current.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android.graphics {
 
   public class ColorMatrix {
diff --git a/libs/hwui/api/module-lib-current.txt b/libs/hwui/api/module-lib-current.txt
index d802177..14191eb 100644
--- a/libs/hwui/api/module-lib-current.txt
+++ b/libs/hwui/api/module-lib-current.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/libs/hwui/api/module-lib-removed.txt b/libs/hwui/api/module-lib-removed.txt
index d802177..14191eb 100644
--- a/libs/hwui/api/module-lib-removed.txt
+++ b/libs/hwui/api/module-lib-removed.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/libs/hwui/api/removed.txt b/libs/hwui/api/removed.txt
index d802177..14191eb 100644
--- a/libs/hwui/api/removed.txt
+++ b/libs/hwui/api/removed.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/libs/hwui/api/system-current.txt b/libs/hwui/api/system-current.txt
index d802177..14191eb 100644
--- a/libs/hwui/api/system-current.txt
+++ b/libs/hwui/api/system-current.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/libs/hwui/api/system-removed.txt b/libs/hwui/api/system-removed.txt
index d802177..14191eb 100644
--- a/libs/hwui/api/system-removed.txt
+++ b/libs/hwui/api/system-removed.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index 7aef7a5..1463945 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -593,7 +593,7 @@
         return result;
     }
 
-    static SkScalar getMetricsInternal(jlong paintHandle, SkFontMetrics *metrics) {
+    static SkScalar getMetricsInternal(jlong paintHandle, SkFontMetrics* metrics, bool useLocale) {
         const int kElegantTop = 2500;
         const int kElegantBottom = -1000;
         const int kElegantAscent = 1900;
@@ -622,6 +622,17 @@
             metrics->fLeading = size * kElegantLeading / 2048;
             spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
         }
+
+        if (useLocale) {
+            minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
+            minikin::MinikinExtent extent =
+                    typeface->fFontCollection->getReferenceExtentForLocale(minikinPaint);
+            metrics->fAscent = std::min(extent.ascent, metrics->fAscent);
+            metrics->fDescent = std::max(extent.descent, metrics->fDescent);
+            metrics->fTop = std::min(metrics->fAscent, metrics->fTop);
+            metrics->fBottom = std::max(metrics->fDescent, metrics->fBottom);
+        }
+
         return spacing;
     }
 
@@ -634,7 +645,7 @@
                 MinikinUtils::getFontExtent(paint, bidiFlags, typeface, buf, start, count, bufSize);
 
         SkFontMetrics metrics;
-        getMetricsInternal(paintHandle, &metrics);
+        getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
 
         metrics.fAscent = extent.ascent;
         metrics.fDescent = extent.descent;
@@ -686,20 +697,21 @@
         }
     }
 
-    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
+    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj,
+                                 jboolean useLocale) {
         SkFontMetrics metrics;
-        SkScalar spacing = getMetricsInternal(paintHandle, &metrics);
+        SkScalar spacing = getMetricsInternal(paintHandle, &metrics, useLocale);
         GraphicsJNI::set_metrics(env, metricsObj, metrics);
         return SkScalarToFloat(spacing);
     }
 
-    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
+    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj,
+                                  jboolean useLocale) {
         SkFontMetrics metrics;
-        getMetricsInternal(paintHandle, &metrics);
+        getMetricsInternal(paintHandle, &metrics, useLocale);
         return GraphicsJNI::set_metrics_int(env, metricsObj, metrics);
     }
 
-
     // ------------------ @CriticalNative ---------------------------
 
     static void reset(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
@@ -1002,19 +1014,19 @@
 
     static jfloat ascent(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle) {
         SkFontMetrics metrics;
-        getMetricsInternal(paintHandle, &metrics);
+        getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
         return SkScalarToFloat(metrics.fAscent);
     }
 
     static jfloat descent(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle) {
         SkFontMetrics metrics;
-        getMetricsInternal(paintHandle, &metrics);
+        getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
         return SkScalarToFloat(metrics.fDescent);
     }
 
     static jfloat getUnderlinePosition(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle) {
         SkFontMetrics metrics;
-        getMetricsInternal(paintHandle, &metrics);
+        getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
         SkScalar position;
         if (metrics.hasUnderlinePosition(&position)) {
             return SkScalarToFloat(position);
@@ -1026,7 +1038,7 @@
 
     static jfloat getUnderlineThickness(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle) {
         SkFontMetrics metrics;
-        getMetricsInternal(paintHandle, &metrics);
+        getMetricsInternal(paintHandle, &metrics, false /* useLocale */);
         SkScalar thickness;
         if (metrics.hasUnderlineThickness(&thickness)) {
             return SkScalarToFloat(thickness);
@@ -1121,9 +1133,9 @@
         {"nSetTextLocales", "(JLjava/lang/String;)I", (void*)PaintGlue::setTextLocales},
         {"nSetFontFeatureSettings", "(JLjava/lang/String;)V",
          (void*)PaintGlue::setFontFeatureSettings},
-        {"nGetFontMetrics", "(JLandroid/graphics/Paint$FontMetrics;)F",
+        {"nGetFontMetrics", "(JLandroid/graphics/Paint$FontMetrics;Z)F",
          (void*)PaintGlue::getFontMetrics},
-        {"nGetFontMetricsInt", "(JLandroid/graphics/Paint$FontMetricsInt;)I",
+        {"nGetFontMetricsInt", "(JLandroid/graphics/Paint$FontMetricsInt;Z)I",
          (void*)PaintGlue::getFontMetricsInt},
 
         // --------------- @CriticalNative ------------------
diff --git a/libs/securebox/tests/Android.bp b/libs/securebox/tests/Android.bp
index 7df546a..80b501d 100644
--- a/libs/securebox/tests/Android.bp
+++ b/libs/securebox/tests/Android.bp
@@ -32,7 +32,7 @@
         "platform-test-annotations",
         "testables",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 230fb07..bf9419fe 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -875,18 +875,7 @@
         /**
          * Sets the attribute describing what is the intended use of the audio signal,
          * such as alarm or ringtone.
-         * @param usage one of {@link AttributeSdkUsage#USAGE_UNKNOWN},
-         *     {@link AttributeSdkUsage#USAGE_MEDIA},
-         *     {@link AttributeSdkUsage#USAGE_VOICE_COMMUNICATION},
-         *     {@link AttributeSdkUsage#USAGE_VOICE_COMMUNICATION_SIGNALLING},
-         *     {@link AttributeSdkUsage#USAGE_ALARM}, {@link AudioAttributes#USAGE_NOTIFICATION},
-         *     {@link AttributeSdkUsage#USAGE_NOTIFICATION_RINGTONE},
-         *     {@link AttributeSdkUsage#USAGE_NOTIFICATION_EVENT},
-         *     {@link AttributeSdkUsage#USAGE_ASSISTANT},
-         *     {@link AttributeSdkUsage#USAGE_ASSISTANCE_ACCESSIBILITY},
-         *     {@link AttributeSdkUsage#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE},
-         *     {@link AttributeSdkUsage#USAGE_ASSISTANCE_SONIFICATION},
-         *     {@link AttributeSdkUsage#USAGE_GAME}.
+         * @param usage the usage to set.
          * @return the same Builder instance.
          */
         public Builder setUsage(@AttributeSdkUsage int usage) {
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index a311296..ceb3858 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -1284,8 +1284,7 @@
          *    {@link AudioFormat#CHANNEL_OUT_SIDE_RIGHT}.
          *    <p> For a valid {@link AudioTrack} channel position mask,
          *    the following conditions apply:
-         *    <br> (1) at most {@link AudioSystem#OUT_CHANNEL_COUNT_MAX} channel positions may be
-         *    used;
+         *    <br> (1) at most eight channel positions may be used;
          *    <br> (2) right/left pairs should be matched.
          *    <p> For input or {@link AudioRecord}, the mask should be
          *    {@link AudioFormat#CHANNEL_IN_MONO} or
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index adc0e16..d9ed6a8 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4659,24 +4659,24 @@
         Objects.requireNonNull(afr);
         Objects.requireNonNull(clientFakeId);
         int status;
-        try {
-            status = getService().requestAudioFocusForTest(afr.getAudioAttributes(),
-                    afr.getFocusGain(),
-                    mICallBack,
-                    mAudioFocusDispatcher,
-                    clientFakeId, "com.android.test.fakeclient",
-                    afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
-                    clientFakeUid, clientTargetSdk);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-        if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
-            // default path with no external focus policy
-            return status;
-        }
-
         BlockingFocusResultReceiver focusReceiver;
         synchronized (mFocusRequestsLock) {
+            try {
+                status = getService().requestAudioFocusForTest(afr.getAudioAttributes(),
+                        afr.getFocusGain(),
+                        mICallBack,
+                        mAudioFocusDispatcher,
+                        clientFakeId, "com.android.test.fakeclient",
+                        afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
+                        clientFakeUid, clientTargetSdk);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
+                // default path with no external focus policy
+                return status;
+            }
+
             focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId);
         }
 
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index 0f962f9..4e61549 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -226,16 +226,15 @@
          *
          * 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}.
+         * @see AudioPresentation#CONTENT_UNKNOWN
+         * @see AudioPresentation#CONTENT_MAIN
+         * @see AudioPresentation#CONTENT_MUSIC_AND_EFFECTS
+         * @see AudioPresentation#CONTENT_VISUALLY_IMPAIRED
+         * @see AudioPresentation#CONTENT_HEARING_IMPAIRED
+         * @see AudioPresentation#CONTENT_DIALOG
+         * @see AudioPresentation#CONTENT_COMMENTARY
+         * @see AudioPresentation#CONTENT_EMERGENCY
+         * @see AudioPresentation#CONTENT_VOICEOVER
          */
         @NonNull public static final Key<Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER =
                 createKey("presentation-content-classifier", Integer.class);
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 73f15f2..1e57be2 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -49,7 +49,7 @@
     oneway void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled);
 
     /** Used for Notification sound playback. */
-    oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa);
+    oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa, float volume);
     oneway void stopAsync();
 
     /** Return the title of the media. */
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 0319f32..8800dc8 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -29,7 +29,6 @@
 import android.media.audiofx.HapticGenerator;
 import android.net.Uri;
 import android.os.RemoteException;
-import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -767,15 +766,4 @@
         @RingtoneMedia int getEnabledMedia();
         VibrationEffect getVibrationEffect();
     }
-
-    /**
-     * Switch for using the new ringtone implementation (RingtoneV1 vs RingtoneV2). This may be
-     * called from both system server and app-side sdk.
-     *
-     * @hide
-     */
-    public static boolean useRingtoneV2() {
-        // TODO(b/293846645): chang eto new flagging infra
-        return SystemProperties.getBoolean("persist.audio.ringtone.use_v2", false);
-    }
 }
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 12db8c0..b5a9ae2 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -42,6 +42,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.vibrator.Flags;
 import android.os.vibrator.persistence.VibrationXmlParser;
 import android.provider.BaseColumns;
 import android.provider.MediaStore;
@@ -607,7 +608,7 @@
 
         Ringtone ringtone;
         Uri positionUri = getRingtoneUri(position);
-        if (Ringtone.useRingtoneV2()) {
+        if (Flags.hapticsCustomizationRingtoneV2Enabled()) {
             mPreviousRingtone = new Ringtone.Builder(
                     mContext, mMediaType, getDefaultAudioAttributes(mType))
                     .setUri(positionUri)
@@ -953,7 +954,7 @@
      * @return A {@link Ringtone} for the given URI, or null.
      */
     public static Ringtone getRingtone(final Context context, Uri ringtoneUri) {
-        if (Ringtone.useRingtoneV2()) {
+        if (Flags.hapticsCustomizationRingtoneV2Enabled()) {
             return new Ringtone.Builder(
                     context, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(-1))
                     .setUri(ringtoneUri)
@@ -970,7 +971,7 @@
             @Nullable VolumeShaper.Configuration volumeShaperConfig,
             AudioAttributes audioAttributes) {
         // TODO: move caller(s) away from this method: inline the builder call.
-        if (Ringtone.useRingtoneV2()) {
+        if (Flags.hapticsCustomizationRingtoneV2Enabled()) {
             return new Ringtone.Builder(context, Ringtone.MEDIA_SOUND, audioAttributes)
                     .setUri(ringtoneUri)
                     .setVolumeShaperConfig(volumeShaperConfig)
diff --git a/media/java/android/media/RingtoneSelection.java b/media/java/android/media/RingtoneSelection.java
index 74f7276..b74b6a3 100644
--- a/media/java/android/media/RingtoneSelection.java
+++ b/media/java/android/media/RingtoneSelection.java
@@ -18,16 +18,23 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.net.Uri;
+import android.os.UserHandle;
+import android.os.vibrator.Flags;
 import android.provider.MediaStore;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Immutable representation a desired ringtone, usually originating from a user preference.
@@ -46,7 +53,7 @@
  * to be internally consistent and reflect effective values - with the exception of not verifying
  * the actual URI content. For example, loading a selection Uri that sets a sound source to
  * {@link #SOUND_SOURCE_URI}, but doesn't also have a sound Uri set, will result in this class
- * instead returning {@link #SOUND_SOURCE_DEFAULT} from {@link #getSoundSource}.
+ * instead returning {@link #SOUND_SOURCE_UNSPECIFIED} from {@link #getSoundSource}.
  *
  * <h2>Storing preferences</h2>
  *
@@ -57,6 +64,7 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(Flags.FLAG_HAPTICS_CUSTOMIZATION_ENABLED)
 public final class RingtoneSelection {
 
     /**
@@ -70,7 +78,7 @@
      * The sound source is not explicitly specified, so it can follow default behavior for its
      * context.
      */
-    public static final int SOUND_SOURCE_DEFAULT = 0;
+    public static final int SOUND_SOURCE_UNSPECIFIED = 0;
 
     /**
      * Sound is explicitly disabled, such as the user having selected "Silent" in the sound picker.
@@ -83,15 +91,25 @@
     public static final int SOUND_SOURCE_URI = 2;
 
     /**
+     * The sound should explicitly use the system default.
+     *
+     * <p>This value isn't valid within the system default itself.
+     */
+    public static final int SOUND_SOURCE_SYSTEM_DEFAULT = 3;
+
+    // Note: Value 4 reserved for possibility of SOURCE_SOURCE_APPLICATION_DEFAULT.
+
+    /**
      * Directive for how to make sound.
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "SOUND_SOURCE_", value = {
             SOUND_SOURCE_UNKNOWN,
-            SOUND_SOURCE_DEFAULT,
+            SOUND_SOURCE_UNSPECIFIED,
             SOUND_SOURCE_OFF,
             SOUND_SOURCE_URI,
+            SOUND_SOURCE_SYSTEM_DEFAULT,
     })
     public @interface SoundSource {}
 
@@ -106,9 +124,9 @@
     /**
      * Vibration source is not explicitly specified. If vibration is enabled, this will use the
      * first available of {@link #VIBRATION_SOURCE_AUDIO_CHANNEL},
-     * {@link #VIBRATION_SOURCE_APPLICATION_PROVIDED}, or system default vibration.
+     * {@link #VIBRATION_SOURCE_APPLICATION_DEFAULT}, or {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}.
      */
-    public static final int VIBRATION_SOURCE_DEFAULT = 0;
+    public static final int VIBRATION_SOURCE_UNSPECIFIED = 0;
 
     /** Specifies that vibration is explicitly disabled for this ringtone. */
     public static final int VIBRATION_SOURCE_OFF = 1;
@@ -117,22 +135,31 @@
     public static final int VIBRATION_SOURCE_URI = 2;
 
     /**
+     * The vibration should explicitly use the system default.
+     *
+     * <p>This value isn't valid within the system default itself.
+     */
+    public static final int VIBRATION_SOURCE_SYSTEM_DEFAULT = 3;
+
+    /**
      * Specifies that vibration should use the vibration provided by the application. This is
      * typically the application's own default for the use-case, provided via
      * {@link Ringtone.Builder#setVibrationEffect}. For notification channels, this is the vibration
      * effect saved on the notification channel.
      *
      * <p>If no vibration is specified by the application, this value behaves if the source was
-     * {@link #VIBRATION_SOURCE_DEFAULT}.
+     * {@link #VIBRATION_SOURCE_UNSPECIFIED}.
+     *
+     * <p>This value isn't valid within the system default.
      */
-    public static final int VIBRATION_SOURCE_APPLICATION_PROVIDED = 3;
+    public static final int VIBRATION_SOURCE_APPLICATION_DEFAULT = 4;
 
     /**
      * Specifies that vibration should use haptic audio channels from the
      * sound Uri. If the sound URI doesn't have haptic channels, then reverts to the order specified
-     * by {@link #VIBRATION_SOURCE_DEFAULT}.
+     * by {@link #VIBRATION_SOURCE_UNSPECIFIED}.
      */
-    // Numeric gap from VIBRATION_SOURCE_APPLICATION_PROVIDED in case we want other common elements.
+    // Numeric gap from VIBRATION_SOURCE_APPLICATION_DEFAULT in case we want other common elements.
     public static final int VIBRATION_SOURCE_AUDIO_CHANNEL = 10;
 
     /**
@@ -151,10 +178,10 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "VIBRATION_SOURCE_", value = {
             VIBRATION_SOURCE_UNKNOWN,
-            VIBRATION_SOURCE_DEFAULT,
+            VIBRATION_SOURCE_UNSPECIFIED,
             VIBRATION_SOURCE_OFF,
             VIBRATION_SOURCE_URI,
-            VIBRATION_SOURCE_APPLICATION_PROVIDED,
+            VIBRATION_SOURCE_APPLICATION_DEFAULT,
             VIBRATION_SOURCE_AUDIO_CHANNEL,
             VIBRATION_SOURCE_HAPTIC_GENERATOR,
     })
@@ -162,9 +189,12 @@
 
     /**
      * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as the sound Uri
-     * for the returned {@link RingtoneSelection}, with null meaning {@link #SOUND_SOURCE_OFF}.
-     * This behavior is particularly suited to loading values from older settings that may contain
-     * a raw sound Uri or null for silent.
+     * for the returned {@link RingtoneSelection}, with null meaning {@link #SOUND_SOURCE_OFF},
+     * and symbolic default URIs ({@link RingtoneManager#getDefaultUri}) meaning
+     * {@link #SOUND_SOURCE_SYSTEM_DEFAULT}.
+     *
+     * <p>This behavior is particularly suited to loading values from older settings that may
+     * contain a raw sound Uri or null for silent.
      *
      * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false.
      */
@@ -173,7 +203,8 @@
     /**
      * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as the vibration
      * Uri for the returned {@link RingtoneSelection}, with null meaning
-     * {@link #VIBRATION_SOURCE_OFF}.
+     * {@link #VIBRATION_SOURCE_OFF} and symbolic default URIs
+     * ({@link RingtoneManager#getDefaultUri}) meaning {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}.
      *
      * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false.
      */
@@ -182,7 +213,9 @@
     /**
      * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as an invalid
      * value. Null or an invalid values will revert to default behavior correspnoding to
-     * {@link #DEFAULT_SELECTION_URI_STRING}.
+     * {@link #DEFAULT_SELECTION_URI_STRING}. Symbolic default URIs
+     * ({@link RingtoneManager#getDefaultUri}) will set both
+     * {@link #SOUND_SOURCE_SYSTEM_DEFAULT} and {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}.
      *
      * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false,
      * which include {@code null}.
@@ -218,10 +251,11 @@
 
     /* Common param values */
     private static final String SOURCE_OFF_STRING = "off";
+    private static final String SOURCE_SYSTEM_DEFAULT_STRING = "sys";
 
     /* Vibration source param values. */
     private static final String VIBRATION_SOURCE_AUDIO_CHANNEL_STRING = "ac";
-    private static final String VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING = "app";
+    private static final String VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING = "app";
     private static final String VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING = "hg";
 
     @Nullable
@@ -236,53 +270,45 @@
 
     private RingtoneSelection(@Nullable Uri soundUri, @SoundSource int soundSource,
             @Nullable Uri vibrationUri, @VibrationSource int vibrationSource) {
-        // Enforce guarantees on the source values: revert to unset if they depend on something
-        // that's not set.
-        switch (soundSource) {
-            case SOUND_SOURCE_URI:
-            case SOUND_SOURCE_UNKNOWN:  // Allow unknown to revert to URI before default.
-                mSoundSource = soundUri != null ? SOUND_SOURCE_URI : SOUND_SOURCE_DEFAULT;
-                break;
-            default:
-                mSoundSource = soundSource;
-                break;
-        }
-        switch (vibrationSource) {
-            case VIBRATION_SOURCE_AUDIO_CHANNEL:
-            case VIBRATION_SOURCE_HAPTIC_GENERATOR:
-                mVibrationSource = soundUri != null ? vibrationSource : VIBRATION_SOURCE_DEFAULT;
-                break;
-            case VIBRATION_SOURCE_URI:
-            case VIBRATION_SOURCE_UNKNOWN:  // Allow unknown to revert to URI.
-                mVibrationSource =
-                        vibrationUri != null ? VIBRATION_SOURCE_URI : VIBRATION_SOURCE_DEFAULT;
-                break;
-            default:
-                mVibrationSource = vibrationSource;
-                break;
-        }
+        // Enforce guarantees on the source values: revert to unspecified if they depend on
+        // something that's not set.
+        //
+        // The non-public "unknown" value can't appear in a getter result, it's just a reserved
+        // "null" value and should be treated the same as an unrecognized value. This can be seen
+        // in Uri parsing. For this and other unrecognized values, we either revert them to the URI
+        // source, if a Uri was included, or the "unspecified" source otherwise. This can be
+        // seen in action in the Uri parsing.
+        //
+        // The "unspecified" source is a public value meaning that there is no specific
+        // behavior indicated, and the defaults and fallbacks should be applied. For example, an
+        // vibration source value of "system default" means to explicitly use the system default
+        // vibration. However, an "unspecified" vibration source will first see if audio coupled
+        // or application-default vibrations are available.
+        mSoundSource = switch (soundSource) {
+            // Supported explicit values that don't have a Uri.
+            case SOUND_SOURCE_OFF, SOUND_SOURCE_UNSPECIFIED, SOUND_SOURCE_SYSTEM_DEFAULT ->
+                    soundSource;
+            // Uri and unknown/unrecognized values: use a Uri if one is present, else revert to
+            // unspecified.
+            default ->
+                soundUri != null ? SOUND_SOURCE_URI : SOUND_SOURCE_UNSPECIFIED;
+        };
+        mVibrationSource = switch (vibrationSource) {
+            // Enforce vibration sources that require a sound Uri.
+            case VIBRATION_SOURCE_AUDIO_CHANNEL, VIBRATION_SOURCE_HAPTIC_GENERATOR ->
+                    soundUri != null ? vibrationSource : VIBRATION_SOURCE_UNSPECIFIED;
+            // Supported explicit values that don't rely on any Uri.
+            case VIBRATION_SOURCE_OFF, VIBRATION_SOURCE_UNSPECIFIED,
+                    VIBRATION_SOURCE_SYSTEM_DEFAULT, VIBRATION_SOURCE_APPLICATION_DEFAULT ->
+                    vibrationSource;
+            // Uri and unknown/unrecognized values: use a Uri if one is present, else revert to
+            // unspecified.
+            default ->
+                    vibrationUri != null ? VIBRATION_SOURCE_URI : VIBRATION_SOURCE_UNSPECIFIED;
+        };
         // Clear Uri values if they're un-used by the source.
-        switch (mSoundSource) {
-            case SOUND_SOURCE_OFF:
-                mSoundUri = null;
-                break;
-            default:
-                // Unset case isn't handled here: the defaulting behavior is left to the player.
-                mSoundUri = soundUri;
-                break;
-        }
-        switch (mVibrationSource) {
-            case VIBRATION_SOURCE_OFF:
-            case VIBRATION_SOURCE_APPLICATION_PROVIDED:
-            case VIBRATION_SOURCE_AUDIO_CHANNEL:
-            case VIBRATION_SOURCE_HAPTIC_GENERATOR:
-                mVibrationUri = null;
-                break;
-            default:
-                // Unset case isn't handled here: the defaulting behavior is left to the player.
-                mVibrationUri = vibrationUri;
-                break;
-        }
+        mSoundUri = mSoundSource == SOUND_SOURCE_URI ? soundUri : null;
+        mVibrationUri = mVibrationSource == VIBRATION_SOURCE_URI ? vibrationUri : null;
     }
 
     /**
@@ -360,18 +386,83 @@
         }
         // Any URI content://media/ringtone
         return ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
-                && MediaStore.AUTHORITY.equals(uri.getAuthority())
+                && MediaStore.AUTHORITY.equals(
+                        ContentProvider.getAuthorityWithoutUserId(uri.getAuthority()))
                 && MEDIA_URI_RINGTONE_PATH.equals(uri.getPath());
     }
 
+    /**
+     * Strip the specified userId from internal Uris. Non-stripped userIds will typically be
+     * for work profiles referencing system ringtones from the host user.
+     *
+     * This is only for use in RingtoneManager.
+     * @hide
+     */
+    @VisibleForTesting
+    public RingtoneSelection getWithoutUserId(int userIdToStrip) {
+        if (mSoundSource != SOUND_SOURCE_URI && mVibrationSource != VIBRATION_SOURCE_URI) {
+            return this;
+        }
 
+        // Ok if uri is null. We only replace explicit references to the specified (current) userId.
+        int soundUserId = ContentProvider.getUserIdFromUri(mSoundUri, UserHandle.USER_NULL);
+        int vibrationUserId = ContentProvider.getUserIdFromUri(mVibrationUri, UserHandle.USER_NULL);
+        boolean needToChangeSound =
+                soundUserId != UserHandle.USER_NULL && soundUserId == userIdToStrip;
+        boolean needToChangeVibration =
+                vibrationUserId != UserHandle.USER_NULL && vibrationUserId == userIdToStrip;
+
+        // Anything to do?
+        if (!needToChangeSound && !needToChangeVibration) {
+            return this;
+        }
+
+        RingtoneSelection.Builder updated = new Builder(this);
+        // The relevant uris can't be null, because they contain userIdToStrip.
+        if (needToChangeSound) {
+            // mSoundUri is not null, so the result of getUriWithoutUserId won't be null.
+            updated.setSoundSource(ContentProvider.getUriWithoutUserId(mSoundUri));
+        }
+        if (needToChangeVibration) {
+            updated.setVibrationSource(ContentProvider.getUriWithoutUserId(mVibrationUri));
+        }
+        return updated.build();
+    }
+
+    @Override
+    public String toString() {
+        return toUri().toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof RingtoneSelection other)) {
+            return false;
+        }
+        return this.mSoundSource == other.mSoundSource
+                && this.mVibrationSource == other.mVibrationSource
+                && Objects.equals(this.mSoundUri, other.mSoundUri)
+                && Objects.equals(this.mVibrationUri, other.mVibrationUri);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSoundSource, mVibrationSource, mSoundUri, mVibrationUri);
+    }
 
     /**
      * Converts a Uri into a RingtoneSelection.
      *
-     * <p>Null values and Uris that {@link #isRingtoneSelectionUri(Uri)} returns false will be
-     * treated according to the behaviour specified by the {@code unrecognizedValueBehavior}
-     * parameter.
+     * <p>Null values, Uris that {@link #isRingtoneSelectionUri(Uri)} returns false (except for
+     * old-style symbolic default Uris {@link RingtoneManager#getDefaultUri}) will be treated
+     * according to the behaviour specified by the {@code unrecognizedValueBehavior} parameter.
+     *
+     * <p>Symbolic default Uris (where {@link RingtoneManager#getDefaultType(Uri)} returns -1,
+     * will map sources to {@link #SOUND_SOURCE_SYSTEM_DEFAULT} and
+     * {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}.
      *
      * @param uri The Uri to convert, potentially null.
      * @param unrecognizedValueBehavior indicates how to treat values for which
@@ -384,21 +475,35 @@
         if (isRingtoneSelectionUri(uri)) {
             return parseRingtoneSelectionUri(uri);
         }
+        // Old symbolic default URIs map to the sources suggested by the unrecognized behavior.
+        // It doesn't always map to both sources because the app may have its own default behavior
+        // to apply, so non-primary sources are left as unspecified, which will revert to the
+        // system default in the absence of an app default.
+        boolean isDefaultUri = RingtoneManager.getDefaultType(uri) > 0;
         RingtoneSelection.Builder builder = new RingtoneSelection.Builder();
         switch (unrecognizedValueBehavior) {
             case FROM_URI_RINGTONE_SELECTION_ONLY:
-                // Always return use-defaults for unrecognized ringtone selection Uris.
+                if (isDefaultUri) {
+                    builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT);
+                    builder.setVibrationSource(VIBRATION_SOURCE_SYSTEM_DEFAULT);
+                }
+                // Always return unspecified (defaults) for unrecognized ringtone selection Uris.
                 return builder.build();
             case FROM_URI_RINGTONE_SELECTION_OR_SOUND:
                 if (uri == null) {
                     return builder.setSoundSource(SOUND_SOURCE_OFF).build();
+                } else if (isDefaultUri) {
+                    return builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT).build();
                 } else {
                     return builder.setSoundSource(uri).build();
                 }
             case FROM_URI_RINGTONE_SELECTION_OR_VIBRATION:
                 if (uri == null) {
                     return builder.setVibrationSource(VIBRATION_SOURCE_OFF).build();
+                } else if (isDefaultUri) {
+                    return builder.setVibrationSource(VIBRATION_SOURCE_SYSTEM_DEFAULT).build();
                 } else {
+                    // Unlike sound, there's no legacy settings alias uri for the default.
                     return builder.setVibrationSource(uri).build();
                 }
             default:
@@ -407,7 +512,12 @@
         }
     }
 
-    /** Parses the Uri, which has already been checked for {@link #isRingtoneSelectionUri(Uri)}. */
+    /**
+     * Parses the Uri, which has already been checked for {@link #isRingtoneSelectionUri(Uri)}.
+     * As a special case to be more compatible, if the RingtoneSelection has a userId specified in
+     * the authority, then this is pushed down into the sound and vibration Uri, as the selection
+     * itself is agnostic.
+     */
     @NonNull
     private static RingtoneSelection parseRingtoneSelectionUri(@NonNull Uri uri) {
         RingtoneSelection.Builder builder = new RingtoneSelection.Builder();
@@ -416,19 +526,39 @@
                 uri.getQueryParameter(URI_PARAM_VIBRATION_SOURCE));
         Uri soundUri = getParamAsUri(uri, URI_PARAM_SOUND_URI);
         Uri vibrationUri = getParamAsUri(uri, URI_PARAM_VIBRATION_URI);
+
+        // Add userId if necessary. This won't override an existing one in the sound/vib Uris.
+        int userIdFromAuthority = ContentProvider.getUserIdFromAuthority(
+                uri.getAuthority(), UserHandle.USER_NULL);
+        if (userIdFromAuthority != UserHandle.USER_NULL) {
+            // Won't override existing user id.
+            if (soundUri != null) {
+                soundUri = ContentProvider.maybeAddUserId(soundUri, userIdFromAuthority);
+            }
+            if (vibrationUri != null) {
+                vibrationUri = ContentProvider.maybeAddUserId(vibrationUri, userIdFromAuthority);
+            }
+        }
+
+        // Set sound uri if present, but map system default Uris to the system default source.
         if (soundUri != null) {
-            builder.setSoundSource(soundUri);
+            if (RingtoneManager.getDefaultType(uri) >= 0) {
+                builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT);
+            } else {
+                builder.setSoundSource(soundUri);
+            }
         }
         if (vibrationUri != null) {
             builder.setVibrationSource(vibrationUri);
         }
+
         // Don't set the source if there's a URI and the source is default, because that will
         // override the Uri source set above. In effect, we prioritise "explicit" sources over
         // an implicit Uri source - except for "default", which isn't really explicit.
-        if (soundSource != SOUND_SOURCE_DEFAULT || soundUri == null) {
+        if (soundSource != SOUND_SOURCE_UNSPECIFIED || soundUri == null) {
             builder.setSoundSource(soundSource);
         }
-        if (vibrationSource != VIBRATION_SOURCE_DEFAULT || vibrationUri == null) {
+        if (vibrationSource != VIBRATION_SOURCE_UNSPECIFIED || vibrationUri == null) {
             builder.setVibrationSource(vibrationSource);
         }
         return builder.build();
@@ -450,26 +580,28 @@
      */
     @Nullable
     private static String soundSourceToString(@SoundSource int soundSource) {
-        switch (soundSource) {
-            case SOUND_SOURCE_OFF: return SOURCE_OFF_STRING;
-            default: return null;
-        }
+        return switch (soundSource) {
+            case SOUND_SOURCE_OFF -> SOURCE_OFF_STRING;
+            case SOUND_SOURCE_SYSTEM_DEFAULT -> SOURCE_SYSTEM_DEFAULT_STRING;
+            default -> null;
+        };
     }
 
     /**
      * Returns the sound source int corresponding to the query string value. Returns
      * {@link #SOUND_SOURCE_UNKNOWN} if the value isn't recognised, and
-     * {@link #SOUND_SOURCE_DEFAULT} if the value is {@code null} (not in the Uri).
+     * {@link #SOUND_SOURCE_UNSPECIFIED} if the value is {@code null} (not in the Uri).
      */
     @SoundSource
     private static int stringToSoundSource(@Nullable String soundSource) {
         if (soundSource == null) {
-            return SOUND_SOURCE_DEFAULT;
+            return SOUND_SOURCE_UNSPECIFIED;
         }
-        switch (soundSource) {
-            case SOURCE_OFF_STRING: return SOUND_SOURCE_OFF;
-            default: return SOUND_SOURCE_UNKNOWN;
-        }
+        return switch (soundSource) {
+            case SOURCE_OFF_STRING -> SOUND_SOURCE_OFF;
+            case SOURCE_SYSTEM_DEFAULT_STRING -> SOUND_SOURCE_SYSTEM_DEFAULT;
+            default -> SOUND_SOURCE_UNKNOWN;
+        };
     }
 
     /**
@@ -478,30 +610,31 @@
      */
     @Nullable
     private static String vibrationSourceToString(@VibrationSource int vibrationSource) {
-        switch (vibrationSource) {
-            case VIBRATION_SOURCE_OFF: return SOURCE_OFF_STRING;
-            case VIBRATION_SOURCE_AUDIO_CHANNEL: return VIBRATION_SOURCE_AUDIO_CHANNEL_STRING;
-            case VIBRATION_SOURCE_HAPTIC_GENERATOR:
-                return VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING;
-            case VIBRATION_SOURCE_APPLICATION_PROVIDED:
-                return VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING;
-            default: return null;
-        }
+        return switch (vibrationSource) {
+            case VIBRATION_SOURCE_OFF -> SOURCE_OFF_STRING;
+            case VIBRATION_SOURCE_AUDIO_CHANNEL -> VIBRATION_SOURCE_AUDIO_CHANNEL_STRING;
+            case VIBRATION_SOURCE_HAPTIC_GENERATOR -> VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING;
+            case VIBRATION_SOURCE_APPLICATION_DEFAULT ->
+                    VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING;
+            case VIBRATION_SOURCE_SYSTEM_DEFAULT -> SOURCE_SYSTEM_DEFAULT_STRING;
+            default -> null;
+        };
     }
 
     @VibrationSource
     private static int stringToVibrationSource(@Nullable String vibrationSource) {
         if (vibrationSource == null) {
-            return VIBRATION_SOURCE_DEFAULT;
+            return VIBRATION_SOURCE_UNSPECIFIED;
         }
-        switch (vibrationSource) {
-            case SOURCE_OFF_STRING: return VIBRATION_SOURCE_OFF;
-            case VIBRATION_SOURCE_AUDIO_CHANNEL_STRING: return VIBRATION_SOURCE_AUDIO_CHANNEL;
-            case VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING: return VIBRATION_SOURCE_HAPTIC_GENERATOR;
-            case VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING:
-                return VIBRATION_SOURCE_APPLICATION_PROVIDED;
-            default: return VIBRATION_SOURCE_UNKNOWN;
-        }
+        return switch (vibrationSource) {
+            case SOURCE_OFF_STRING -> VIBRATION_SOURCE_OFF;
+            case SOURCE_SYSTEM_DEFAULT_STRING -> VIBRATION_SOURCE_SYSTEM_DEFAULT;
+            case VIBRATION_SOURCE_AUDIO_CHANNEL_STRING -> VIBRATION_SOURCE_AUDIO_CHANNEL;
+            case VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING -> VIBRATION_SOURCE_HAPTIC_GENERATOR;
+            case VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING ->
+                    VIBRATION_SOURCE_APPLICATION_DEFAULT;
+            default -> VIBRATION_SOURCE_UNKNOWN;
+        };
     }
 
     /**
@@ -512,12 +645,13 @@
     public static final class Builder {
         private Uri mSoundUri;
         private Uri mVibrationUri;
-        @SoundSource private int mSoundSource = SOUND_SOURCE_DEFAULT;
-        @VibrationSource private int mVibrationSource = VIBRATION_SOURCE_DEFAULT;
+        @SoundSource private int mSoundSource = SOUND_SOURCE_UNSPECIFIED;
+        @VibrationSource private int mVibrationSource = VIBRATION_SOURCE_UNSPECIFIED;
 
         /**
          * Creates a new {@link RingtoneSelection} builder. A default ringtone selection has its
-         * sound and vibration source unset, which means they would fall back to system defaults.
+         * sound and vibration source unspecified, which means they would fall back to app/system
+         * defaults.
          */
         public Builder() {}
 
@@ -559,7 +693,9 @@
          */
         @NonNull
         public Builder setSoundSource(@NonNull Uri soundUri) {
-            mSoundUri = requireNonNull(soundUri);
+            // getCanonicalUri shouldn't return null. If it somehow did, then the
+            // RingtoneSelection constructor will revert this to unspecified.
+            mSoundUri = requireNonNull(soundUri).getCanonicalUri();
             mSoundSource = SOUND_SOURCE_URI;
             return this;
         }
@@ -587,7 +723,9 @@
          */
         @NonNull
         public Builder setVibrationSource(@NonNull Uri vibrationUri) {
-            mVibrationUri = requireNonNull(vibrationUri);
+            // getCanonicalUri shouldn't return null. If it somehow did, then the
+            // RingtoneSelection constructor will revert this to unspecified.
+            mVibrationUri = requireNonNull(vibrationUri).getCanonicalUri();
             mVibrationSource = VIBRATION_SOURCE_URI;
             return this;
         }
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 83d2b61..a354f91 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -15,8 +15,15 @@
 }
 
 flag {
-     namespace: "media_solutions"
-     name: "enable_audio_policies_device_and_bluetooth_controller"
-     description: "Use Audio Policies implementation for device and Bluetooth route controllers."
-     bug: "280576228"
+    namespace: "media_solutions"
+    name: "enable_audio_policies_device_and_bluetooth_controller"
+    description: "Use Audio Policies implementation for device and Bluetooth route controllers."
+    bug: "280576228"
+}
+
+flag {
+    namespace: "media_solutions"
+    name: "disable_screen_off_broadcast_receiver"
+    description: "Disables the broadcast receiver that prevents scanning when the screen is off."
+    bug: "304234628"
 }
diff --git a/media/java/android/media/tv/SectionRequest.java b/media/java/android/media/tv/SectionRequest.java
index 078e832..ec0d7f7 100644
--- a/media/java/android/media/tv/SectionRequest.java
+++ b/media/java/android/media/tv/SectionRequest.java
@@ -81,7 +81,7 @@
     /**
      * Gets the version number of requested session. If it is null, value will be -1.
      * <p>The consistency of version numbers between request and response depends on
-     * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+     * {@link BroadcastInfoRequest#getOption()}. If the request has RequestOption value
      * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
      * different from the version of the request. Otherwise, response with a different version from
      * its request will be considered invalid.
diff --git a/media/java/android/media/tv/SectionResponse.java b/media/java/android/media/tv/SectionResponse.java
index f38ea9d..10333fe 100644
--- a/media/java/android/media/tv/SectionResponse.java
+++ b/media/java/android/media/tv/SectionResponse.java
@@ -76,7 +76,7 @@
     /**
      * Gets the Version number of requested session. If it is null, value will be -1.
      * <p>The consistency of version numbers between request and response depends on
-     * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+     * {@link BroadcastInfoRequest#getOption()}. If the request has RequestOption value
      * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
      * different from the version of the request. Otherwise, response with a different version from
      * its request will be considered invalid.
diff --git a/media/java/android/media/tv/TableRequest.java b/media/java/android/media/tv/TableRequest.java
index d9587f6..06df07f 100644
--- a/media/java/android/media/tv/TableRequest.java
+++ b/media/java/android/media/tv/TableRequest.java
@@ -129,7 +129,7 @@
     /**
      * Gets the version number of requested table. If it is null, value will be -1.
      * <p>The consistency of version numbers between request and response depends on
-     * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+     * {@link BroadcastInfoRequest#getOption()}. If the request has RequestOption value
      * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
      * different from the version of the request. Otherwise, response with a different version from
      * its request will be considered invalid.
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index c4fc26e..1daf452 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -269,7 +269,7 @@
     /**
      * Gets the version number of requested table. If it is null, value will be -1.
      * <p>The consistency of version numbers between request and response depends on
-     * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+     * {@link BroadcastInfoRequest#getOption()}. If the request has RequestOption value
      * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
      * different from the version of the request. Otherwise, response with a different version from
      * its request will be considered invalid.
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 667a9ae..13f7743 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -939,9 +939,10 @@
                 type = TYPE_HDMI;
                 isHardwareInput = true;
                 hdmiConnectionRelativePosition = getRelativePosition(mContext, mHdmiDeviceInfo);
-                isConnectedToHdmiSwitch =
-                        hdmiConnectionRelativePosition
-                                != HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW;
+                isConnectedToHdmiSwitch = hdmiConnectionRelativePosition
+                                != HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW
+                        && hdmiConnectionRelativePosition
+                                != HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN;
             } else if (mTvInputHardwareInfo != null) {
                 id = generateInputId(componentName, mTvInputHardwareInfo);
                 type = sHardwareTypeToTvInputType.get(mTvInputHardwareInfo.getType(), TYPE_TUNER);
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index c616b84f..1c25080 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -38,6 +38,8 @@
 #include <mediadrm/IDrmMetricsConsumer.h>
 #include <mediadrm/IDrm.h>
 #include <utils/Vector.h>
+#include <map>
+#include <string>
 
 using ::android::os::PersistableBundle;
 namespace drm = ::android::hardware::drm;
@@ -193,6 +195,11 @@
     jclass classId;
 };
 
+struct DrmExceptionFields {
+    jmethodID init;
+    jclass classId;
+};
+
 struct fields_t {
     jfieldID context;
     jmethodID post_event;
@@ -215,6 +222,7 @@
     jclass parcelCreatorClassId;
     KeyStatusFields keyStatus;
     LogMessageFields logMessage;
+    std::map<std::string, DrmExceptionFields> exceptionCtors;
 };
 
 static fields_t gFields;
@@ -245,18 +253,32 @@
     return arrayList;
 }
 
-int drmThrowException(JNIEnv* env, const char *className, const DrmStatus &err, const char *msg) {
+void resolveDrmExceptionCtor(JNIEnv *env, const char *className) {
+    jclass clazz;
+    jmethodID init;
+    FIND_CLASS(clazz, className);
+    GET_METHOD_ID(init, clazz, "<init>", "(Ljava/lang/String;III)V");
+    gFields.exceptionCtors[std::string(className)] = {
+        .init = init,
+        .classId = static_cast<jclass>(env->NewGlobalRef(clazz))
+        };
+}
+
+void drmThrowException(JNIEnv* env, const char *className, const DrmStatus &err, const char *msg) {
     using namespace android::jnihelp;
-    jstring _detailMessage = CreateExceptionMsg(env, msg);
-    int _status = ThrowException(env, className, "(Ljava/lang/String;III)V",
-                                 _detailMessage,
-                                 err.getCdmErr(),
-                                 err.getOemErr(),
-                                 err.getContext());
-    if (_detailMessage != NULL) {
-        env->DeleteLocalRef(_detailMessage);
+
+    if (gFields.exceptionCtors.count(std::string(className)) == 0) {
+        jniThrowException(env, className, msg);
+    } else {
+        jstring _detailMessage = CreateExceptionMsg(env, msg);
+        jobject exception = env->NewObject(gFields.exceptionCtors[std::string(className)].classId,
+            gFields.exceptionCtors[std::string(className)].init, _detailMessage,
+            err.getCdmErr(), err.getOemErr(), err.getContext());
+        env->Throw(static_cast<jthrowable>(exception));
+        if (_detailMessage != NULL) {
+            env->DeleteLocalRef(_detailMessage);
+        }
     }
-    return _status;
 }
 }  // namespace anonymous
 
@@ -952,6 +974,10 @@
     FIND_CLASS(clazz, "android/media/MediaDrm$LogMessage");
     gFields.logMessage.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
     GET_METHOD_ID(gFields.logMessage.init, clazz, "<init>", "(JILjava/lang/String;)V");
+
+    resolveDrmExceptionCtor(env, "android/media/NotProvisionedException");
+    resolveDrmExceptionCtor(env, "android/media/ResourceBusyException");
+    resolveDrmExceptionCtor(env, "android/media/DeniedByServerException");
 }
 
 static void android_media_MediaDrm_native_setup(
@@ -2192,4 +2218,4 @@
 int register_android_media_Drm(JNIEnv *env) {
     return AndroidRuntime::registerNativeMethods(env,
                 "android/media/MediaDrm", gMethods, NELEM(gMethods));
-}
+}
\ No newline at end of file
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
index ca20225e..bdd7afe 100644
--- a/media/tests/MediaFrameworkTest/Android.bp
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -22,7 +22,7 @@
         "android-ex-camera2",
         "testables",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: [
         "libdexmakerjvmtiagent",
diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp
index 4cccf89..61b18c8 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/Android.bp
@@ -24,7 +24,7 @@
         "compatibility-device-util-axt",
         "mockito-target-minus-junit4",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: ["general-tests"],
     platform_apis: true,
diff --git a/media/tests/projection/Android.bp b/media/tests/projection/Android.bp
index e313c46..48cd8b6 100644
--- a/media/tests/projection/Android.bp
+++ b/media/tests/projection/Android.bp
@@ -30,7 +30,7 @@
         "platform-test-annotations",
         "testng",
         "testables",
-        "truth-prebuilt",
+        "truth",
         "platform-compat-test-rules",
     ],
 
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 7ca172e..4eb8de6 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -37,7 +37,7 @@
     <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Zezwolić urządzeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; na wykonanie tego działania?"</string>
     <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o uprawnienia do strumieniowego odtwarzania treści i innych funkcji systemowych na urządzeniach w pobliżu"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
-    <string name="summary_generic" msgid="1761976003668044801">"Ta aplikacja może synchronizować informacje takie jak nazwa osoby dzwoniącej między Twoim telefonem i wybranym urządzeniem"</string>
+    <string name="summary_generic" msgid="1761976003668044801">"Ta aplikacja może synchronizować informacje takie jak imię i nazwisko osoby dzwoniącej między Twoim telefonem i wybranym urządzeniem"</string>
     <string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Anuluj"</string>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
index 118a77c..c25fa99 100644
--- a/packages/CredentialManager/res/values-hu/strings.xml
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -70,7 +70,7 @@
     <string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Elvetés"</string>
     <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Szeretné a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz mentett azonosítókulcsot használni?"</string>
     <string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Szeretné az elmentett jelszavát használni a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz?"</string>
-    <string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Szeretné használni a következőhöz tartozó bejelentkezési adatait: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Szeretné használni bejelentkezési adatait a következőhöz: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Feloldja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> bejelentkezési lehetőségeit?"</string>
     <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Mentett azonosítókulcs kiválasztása a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz"</string>
     <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Mentett jelszó kiválasztása a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz"</string>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index ed42f3a..8125ec6 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -70,12 +70,12 @@
     <string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"დახურვა"</string>
     <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"გსურთ თქვენი დამახსოვრებული წვდომის გასაღების გამოყენება აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="get_dialog_title_use_password_for" msgid="625828023234318484">"გამოიყენებთ შენახულ პაროლს <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის?"</string>
-    <string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"გსურთ შესვლის <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის გამოყენება?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"გსურთ შესვლის <xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის გამოყენება?"</string>
     <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"გსურთ შესვლის ვარიანტების განბლოკვა <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის?"</string>
     <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"აირჩიეთ შენახული წვდომის გასაღები <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის"</string>
     <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"აირჩიეთ შენახული პაროლი <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის"</string>
     <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"აირჩიეთ სისტემაში შესვლის ინფორმაცია <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის"</string>
-    <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"აირჩიეთ შესვლა <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"აირჩიეთ შესვლა <xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის"</string>
     <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"გსურთ აირჩიოთ ვარიანტი <xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის?"</string>
     <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"გსურთ ამ ინფორმაციის გამოყენება <xliff:g id="APP_NAME">%1$s</xliff:g>-ში?"</string>
     <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"სხვა ხერხით შესვლა"</string>
diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml
index b4c5670..e2de2ef 100644
--- a/packages/CredentialManager/res/values-ky/strings.xml
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -70,12 +70,12 @@
     <string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Жабуу"</string>
     <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна кирүү үчүн сакталган ачкычты колдоносузбу?"</string>
     <string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн сакталган сырсөздү колдоносузбу?"</string>
-    <string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна кирүү жолун тандайсызбы?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна төмөнкү аккаунт менен киресизби?"</string>
     <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн кирүү параметрлеринин кулпусу ачылсынбы?"</string>
     <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн сакталган киргизүүчү ачкычты тандаңыз"</string>
     <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн сакталган сырсөздү тандаңыз"</string>
     <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн кирүү маалыматын тандаңыз"</string>
-    <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна кирүү жолун тандаңыз"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна кайсы аккаунт менен киресиз:"</string>
     <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн параметр тандайсызбы?"</string>
     <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Бул маалыматты <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда пайдаланасызбы?"</string>
     <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Башка жол менен кирүү"</string>
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
index 15a668a..222b865 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -70,7 +70,7 @@
     <string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"忽略"</string>
     <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"要使用您为“<xliff:g id="APP_NAME">%1$s</xliff:g>”保存的通行密钥吗?"</string>
     <string name="get_dialog_title_use_password_for" msgid="625828023234318484">"要使用已保存的密码登录“<xliff:g id="APP_NAME">%1$s</xliff:g>”吗?"</string>
-    <string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"使用您的<xliff:g id="APP_NAME">%1$s</xliff:g>登录凭据?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"是否使用您的<xliff:g id="APP_NAME">%1$s</xliff:g>登录凭据继续?"</string>
     <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"要解锁“<xliff:g id="APP_NAME">%1$s</xliff:g>”的登录选项吗?"</string>
     <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"选择一个已保存的通行密钥来登录“<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
     <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"选择一个已保存的密码来登录“<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml
index f14a5ce..c09bf86 100644
--- a/packages/CredentialManager/res/values-zh-rTW/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="4539824758261855508">"憑證管理工具"</string>
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
     <string name="string_cancel" msgid="6369133483981306063">"取消"</string>
     <string name="string_continue" msgid="1346732695941131882">"繼續"</string>
     <string name="string_more_options" msgid="2763852250269945472">"儲存其他方式"</string>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 473d7b6f..477e61d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -61,14 +61,20 @@
 import androidx.credentials.provider.PublicKeyCredentialEntry
 import androidx.credentials.provider.RemoteEntry
 import org.json.JSONObject
+import android.credentials.flags.Flags
 import java.time.Instant
 
+
 fun getAppLabel(
     pm: PackageManager,
     appPackageName: String
 ): String? {
     return try {
-        val pkgInfo = getPackageInfo(pm, appPackageName)
+        val pkgInfo = if (Flags.instantAppsEnabled()) {
+            getPackageInfo(pm, appPackageName)
+        } else {
+            pm.getPackageInfo(appPackageName, PackageManager.PackageInfoFlags.of(0))
+        }
         val applicationInfo = checkNotNull(pkgInfo.applicationInfo)
         applicationInfo.loadSafeLabel(
             pm, 0f,
@@ -91,7 +97,14 @@
         // Test data has only package name not component name.
         // For test data usage only.
         try {
-            val pkgInfo = getPackageInfo(pm, providerFlattenedComponentName)
+            val pkgInfo = if (Flags.instantAppsEnabled()) {
+                getPackageInfo(pm, providerFlattenedComponentName)
+            } else {
+                pm.getPackageInfo(
+                        providerFlattenedComponentName,
+                        PackageManager.PackageInfoFlags.of(0)
+                )
+            }
             val applicationInfo = checkNotNull(pkgInfo.applicationInfo)
             providerLabel =
                 applicationInfo.loadSafeLabel(
@@ -115,7 +128,14 @@
             // Added for mdoc use case where the provider may not need to register a service and
             // instead only relies on the registration api.
             try {
-                val pkgInfo = getPackageInfo(pm, providerFlattenedComponentName)
+                val pkgInfo = if (Flags.instantAppsEnabled()) {
+                    getPackageInfo(pm, providerFlattenedComponentName)
+                } else {
+                    pm.getPackageInfo(
+                            component.packageName,
+                            PackageManager.PackageInfoFlags.of(0)
+                    )
+                }
                 val applicationInfo = checkNotNull(pkgInfo.applicationInfo)
                 providerLabel =
                     applicationInfo.loadSafeLabel(
@@ -143,12 +163,12 @@
     pm: PackageManager,
     packageName: String
 ): PackageInfo {
-    val flags = PackageManager.MATCH_INSTANT
+    val packageManagerFlags = PackageManager.MATCH_INSTANT
 
     return pm.getPackageInfo(
        packageName,
        PackageManager.PackageInfoFlags.of(
-               (flags).toLong())
+               (packageManagerFlags).toLong())
     )
 }
 
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index ba88484..9355517 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -18,21 +18,31 @@
 
 import android.app.assist.AssistStructure
 import android.content.Context
-import android.credentials.GetCredentialRequest
 import android.credentials.CredentialManager
-import android.credentials.GetCandidateCredentialsResponse
 import android.credentials.CredentialOption
 import android.credentials.GetCandidateCredentialsException
+import android.credentials.GetCandidateCredentialsResponse
+import android.credentials.GetCredentialRequest
 import android.os.Bundle
 import android.os.CancellationSignal
 import android.os.OutcomeReceiver
-import android.service.autofill.FillRequest
 import android.service.autofill.AutofillService
-import android.service.autofill.FillResponse
+import android.service.autofill.Dataset
+import android.service.autofill.Field
 import android.service.autofill.FillCallback
-import android.service.autofill.SaveRequest
+import android.service.autofill.FillRequest
+import android.service.autofill.FillResponse
+import android.service.autofill.InlinePresentation
+import android.service.autofill.Presentations
 import android.service.autofill.SaveCallback
+import android.service.autofill.SaveRequest
+import android.service.credentials.CredentialProviderService
 import android.util.Log
+import android.view.autofill.AutofillId
+import org.json.JSONException
+import android.widget.inline.InlinePresentationSpec
+import androidx.autofill.inline.v1.InlineSuggestionUi
+import com.android.credentialmanager.GetFlowUtils
 import org.json.JSONObject
 import java.util.concurrent.Executors
 
@@ -47,11 +57,9 @@
         private const val SYS_PROVIDER_REQ_KEY = "isSystemProviderRequired"
         private const val CRED_OPTIONS_KEY = "credentialOptions"
         private const val TYPE_KEY = "type"
+        private const val REQ_TYPE_KEY = "get"
     }
 
-    private val credentialManager: CredentialManager =
-            getSystemService(Context.CREDENTIAL_SERVICE) as CredentialManager
-
     override fun onFillRequest(
             request: FillRequest,
             cancellationSignal: CancellationSignal,
@@ -64,16 +72,24 @@
 
         val getCredRequest: GetCredentialRequest? = getCredManRequest(structure)
         if (getCredRequest == null) {
+            Log.i(TAG, "No credential manager request found")
             callback.onFailure("No credential manager request found")
             return
         }
+        val credentialManager: CredentialManager =
+                getSystemService(Context.CREDENTIAL_SERVICE) as CredentialManager
 
         val outcome = object : OutcomeReceiver<GetCandidateCredentialsResponse,
                 GetCandidateCredentialsException> {
             override fun onResult(result: GetCandidateCredentialsResponse) {
                 Log.i(TAG, "getCandidateCredentials onResponse")
-                val fillResponse: FillResponse? = convertToFillResponse(result, request)
-                callback.onSuccess(fillResponse)
+                val fillResponse = convertToFillResponse(result, request)
+                if (fillResponse != null) {
+                    callback.onSuccess(fillResponse)
+                } else {
+                    Log.e(TAG, "Failed to create a FillResponse from the CredentialResponse.")
+                    callback.onFailure("No dataset was created from the CredentialResponse")
+                }
             }
 
             override fun onError(error: GetCandidateCredentialsException) {
@@ -95,7 +111,74 @@
             getCredResponse: GetCandidateCredentialsResponse,
             filLRequest: FillRequest
     ): FillResponse? {
-        TODO("Not yet implemented")
+        val providerList = GetFlowUtils.toProviderList(
+                getCredResponse.candidateProviderDataList,
+                this@CredentialAutofillService)
+        var totalEntryCount = 0
+        providerList.forEach { provider ->
+            totalEntryCount += provider.credentialEntryList.size
+        }
+        val inlineSuggestionsRequest = filLRequest.inlineSuggestionsRequest
+        val inlineMaxSuggestedCount = inlineSuggestionsRequest?.maxSuggestionCount ?: 0
+        val inlinePresentationSpecs = inlineSuggestionsRequest?.inlinePresentationSpecs
+        val inlinePresentationSpecsCount = inlinePresentationSpecs?.size ?: 0
+        var maxItemCount = totalEntryCount
+        if (inlineMaxSuggestedCount > 0) {
+            maxItemCount = maxItemCount.coerceAtMost(inlineMaxSuggestedCount)
+        }
+        var i = 0
+        val fillResponseBuilder = FillResponse.Builder()
+        var emptyFillResponse = true
+        providerList.forEach {provider ->
+            // TODO(b/299321128): Before iterating the list, sort the list so that
+            //  the relevant entries don't get truncated
+            provider.credentialEntryList.forEach entryLoop@ {entry ->
+                val autofillId: AutofillId? = entry.fillInIntent?.getParcelableExtra(
+                        CredentialProviderService.EXTRA_AUTOFILL_ID,
+                        AutofillId::class.java)
+                val pendingIntent = entry.pendingIntent
+                if (autofillId == null || pendingIntent == null) {
+                    return@entryLoop
+                }
+                var inlinePresentation: InlinePresentation? = null
+                // Create inline presentation
+                if (inlinePresentationSpecs != null && i < maxItemCount) {
+                    val spec: InlinePresentationSpec
+                    if (i < inlinePresentationSpecsCount) {
+                        spec = inlinePresentationSpecs[i]
+                    } else {
+                        spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
+                    }
+                    val sliceBuilder = InlineSuggestionUi
+                            .newContentBuilder(pendingIntent)
+                            .setTitle(entry.userName)
+                    inlinePresentation = InlinePresentation(
+                            sliceBuilder.build().slice, spec, /* pinned= */ false)
+                }
+                i++
+
+                val dataSetBuilder = Dataset.Builder()
+                val presentationBuilder = Presentations.Builder()
+                if (inlinePresentation != null) {
+                    presentationBuilder.setInlinePresentation(inlinePresentation)
+                }
+                fillResponseBuilder.addDataset(
+                        dataSetBuilder
+                                .setField(
+                                        autofillId,
+                                        Field.Builder().setPresentations(
+                                                presentationBuilder.build())
+                                                .build())
+                                .setAuthentication(entry.pendingIntent.intentSender)
+                                .setAuthenticationExtras(entry.fillInIntent.extras)
+                                .build())
+                emptyFillResponse = false
+            }
+        }
+        if (emptyFillResponse) {
+            return null
+        }
+        return fillResponseBuilder.build()
     }
 
     override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
@@ -129,27 +212,31 @@
     }
 
     private fun traverseNode(
-            viewNode: AssistStructure.ViewNode?,
+            viewNode: AssistStructure.ViewNode,
             cmRequests: MutableList<CredentialOption>
     ) {
-        val options = getCredentialOptionsFromViewNode(viewNode)
-        cmRequests.addAll(options)
+        viewNode.autofillId?.let {
+            val options = getCredentialOptionsFromViewNode(viewNode, it)
+            cmRequests.addAll(options)
+        }
 
-        val children: List<AssistStructure.ViewNode>? =
-                viewNode?.run {
+        val children: List<AssistStructure.ViewNode> =
+                viewNode.run {
                     (0 until childCount).map { getChildAt(it) }
                 }
 
-        children?.forEach { childNode: AssistStructure.ViewNode ->
+        children.forEach { childNode: AssistStructure.ViewNode ->
             traverseNode(childNode, cmRequests)
         }
     }
 
-    private fun getCredentialOptionsFromViewNode(viewNode: AssistStructure.ViewNode?):
-            List<CredentialOption> {
+    private fun getCredentialOptionsFromViewNode(
+            viewNode: AssistStructure.ViewNode,
+            autofillId: AutofillId
+    ): List<CredentialOption> {
         // TODO(b/293945193) Replace with isCredential check from viewNode
         val credentialHints: MutableList<String> = mutableListOf()
-        if (viewNode != null && viewNode.autofillHints != null) {
+        if (viewNode.autofillHints != null) {
             for (hint in viewNode.autofillHints!!) {
                 if (hint.startsWith(CRED_HINT_PREFIX)) {
                     credentialHints.add(hint.substringAfter(CRED_HINT_PREFIX))
@@ -159,25 +246,35 @@
 
         val credentialOptions: MutableList<CredentialOption> = mutableListOf()
         for (credentialHint in credentialHints) {
-            convertJsonToCredentialOption(credentialHint).let { credentialOptions.addAll(it) }
+            try {
+                convertJsonToCredentialOption(credentialHint, autofillId)
+                        .let { credentialOptions.addAll(it) }
+            } catch (e: JSONException) {
+                Log.i(TAG, "Exception while parsing response: " + e.message)
+            }
         }
         return credentialOptions
     }
 
-    private fun convertJsonToCredentialOption(jsonString: String): List<CredentialOption> {
+    private fun convertJsonToCredentialOption(jsonString: String, autofillId: AutofillId):
+            List<CredentialOption> {
         // TODO(b/302000646) Move this logic to jetpack so that is consistent
         //  with building the json
         val credentialOptions: MutableList<CredentialOption> = mutableListOf()
 
         val json = JSONObject(jsonString)
-        val options = json.getJSONArray(CRED_OPTIONS_KEY)
+        val jsonGet = json.getJSONObject(REQ_TYPE_KEY)
+        val options = jsonGet.getJSONArray(CRED_OPTIONS_KEY)
         for (i in 0 until options.length()) {
             val option = options.getJSONObject(i)
-
+            val candidateBundle = convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY))
+            candidateBundle.putParcelable(
+                    CredentialProviderService.EXTRA_AUTOFILL_ID,
+                    autofillId)
             credentialOptions.add(CredentialOption(
                     option.getString(TYPE_KEY),
                     convertJsonToBundle(option.getJSONObject(REQUEST_DATA_KEY)),
-                    convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)),
+                    candidateBundle,
                     option.getBoolean(SYS_PROVIDER_REQ_KEY),
             ))
         }
diff --git a/packages/ExternalStorageProvider/tests/Android.bp b/packages/ExternalStorageProvider/tests/Android.bp
index 633f186..86c62ef 100644
--- a/packages/ExternalStorageProvider/tests/Android.bp
+++ b/packages/ExternalStorageProvider/tests/Android.bp
@@ -25,7 +25,7 @@
     static_libs: [
         "androidx.test.rules",
         "mockito-target",
-        "truth-prebuilt",
+        "truth",
     ],
 
     certificate: "platform",
diff --git a/packages/FusedLocation/Android.bp b/packages/FusedLocation/Android.bp
index 64b4c54..61a8270 100644
--- a/packages/FusedLocation/Android.bp
+++ b/packages/FusedLocation/Android.bp
@@ -47,7 +47,7 @@
     test_config: "test/AndroidTest.xml",
     srcs: [
         "test/src/**/*.java",
-        "src/**/*.java",  // include real sources because we're forced to test this directly
+        "src/**/*.java", // include real sources because we're forced to test this directly
     ],
     libs: [
         "android.test.base",
@@ -60,9 +60,9 @@
         "androidx.test.ext.junit",
         "androidx.test.ext.truth",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     platform_apis: true,
     certificate: "platform",
-    test_suites: ["device-tests"]
+    test_suites: ["device-tests"],
 }
diff --git a/packages/InputDevices/res/raw/keyboard_layout_brazilian.kcm b/packages/InputDevices/res/raw/keyboard_layout_brazilian.kcm
index ad3199f..d9338b1 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_brazilian.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_brazilian.kcm
@@ -337,7 +337,7 @@
     label:                              'M'
     base:                               'm'
     shift, capslock:                    'M'
-    shift+capslock:                     'n'
+    shift+capslock:                     'm'
 }
 
 key COMMA {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm
index 6744922..fc53cba 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm
@@ -12,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
-
-type FULL
+type OVERLAY
 
 ### Basic QWERTY keys ###
 
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index 88bb30b..7f23f74 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -227,13 +227,6 @@
         android:label="@string/keyboard_layout_turkish"
         android:keyboardLayout="@raw/keyboard_layout_turkish"
         android:keyboardLocale="tr-Latn"
-        android:keyboardLayoutType="qwerty" />
-
-    <keyboard-layout
-        android:name="keyboard_layout_turkish"
-        android:label="@string/keyboard_layout_turkish"
-        android:keyboardLayout="@raw/keyboard_layout_turkish"
-        android:keyboardLocale="tr-Latn"
         android:keyboardLayoutType="turkish_q" />
 
     <keyboard-layout
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index d97fb54..c5ae4a3 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -381,7 +381,7 @@
             final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID,
                     -1 /* defaultValue */);
             final SessionInfo info = mInstaller.getSessionInfo(sessionId);
-            String resolvedPath = info.getResolvedBaseApkPath();
+            String resolvedPath = info != null ? info.getResolvedBaseApkPath() : null;
             if (info == null || !info.isSealed() || resolvedPath == null) {
                 Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
                 finish();
@@ -609,7 +609,7 @@
                 CharSequence label = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
                 if (mLocalLOGV) Log.i(TAG, "creating snippet for " + label);
                 mAppSnippet = new PackageUtil.AppSnippet(label,
-                        mPm.getApplicationIcon(mPkgInfo.applicationInfo));
+                        mPm.getApplicationIcon(mPkgInfo.applicationInfo), getBaseContext());
             } break;
 
             case ContentResolver.SCHEME_FILE: {
@@ -647,7 +647,7 @@
         mPkgInfo = generateStubPackageInfo(info.getAppPackageName());
         mAppSnippet = new PackageUtil.AppSnippet(info.getAppLabel(),
                 info.getAppIcon() != null ? new BitmapDrawable(getResources(), info.getAppIcon())
-                        : getPackageManager().getDefaultActivityIcon());
+                        : getPackageManager().getDefaultActivityIcon(), getBaseContext());
         return true;
     }
 
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index 334886f..8de12d0 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -18,6 +18,7 @@
 package com.android.packageinstaller;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
@@ -135,15 +136,20 @@
     static final class AppSnippet implements Parcelable {
         @NonNull public CharSequence label;
         @Nullable public Drawable icon;
-        public AppSnippet(@NonNull CharSequence label, @Nullable Drawable icon) {
+        public int iconSize;
+
+        AppSnippet(@NonNull CharSequence label, @Nullable Drawable icon, Context context) {
             this.label = label;
             this.icon = icon;
+            final ActivityManager am = context.getSystemService(ActivityManager.class);
+            this.iconSize = am.getLauncherLargeIconSize();
         }
 
         private AppSnippet(Parcel in) {
             label = in.readString();
             Bitmap bmp = in.readParcelable(getClass().getClassLoader(), Bitmap.class);
             icon = new BitmapDrawable(Resources.getSystem(), bmp);
+            iconSize = in.readInt();
         }
 
         @Override
@@ -161,11 +167,12 @@
             dest.writeString(label.toString());
             Bitmap bmp = getBitmapFromDrawable(icon);
             dest.writeParcelable(bmp, 0);
+            dest.writeInt(iconSize);
         }
 
         private Bitmap getBitmapFromDrawable(Drawable drawable) {
             // Create an empty bitmap with the dimensions of our drawable
-            final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+            Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                     drawable.getIntrinsicHeight(),
                     Bitmap.Config.ARGB_8888);
             // Associate it with a canvas. This canvas will draw the icon on the bitmap
@@ -174,6 +181,10 @@
             // bitmap held within
             drawable.draw(canvas);
 
+            // Scale it down if the icon is too large
+            if ((bmp.getWidth() > iconSize * 2) || (bmp.getHeight() > iconSize * 2)) {
+                bmp = Bitmap.createScaledBitmap(bmp, iconSize, iconSize, true);
+            }
             return bmp;
         }
 
@@ -241,7 +252,7 @@
         } catch (OutOfMemoryError e) {
             Log.i(LOG_TAG, "Could not load app icon", e);
         }
-        return new PackageUtil.AppSnippet(label, icon);
+        return new PackageUtil.AppSnippet(label, icon, pContext);
     }
 
     private static String findFilePath(File[] files, String postfix) {
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 2d231f2..8964ada 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -11,29 +11,42 @@
     name: "SettingsLib",
 
     static_libs: [
-        "androidx.annotation_annotation",
-        "androidx.appcompat_appcompat",
-        "androidx.coordinatorlayout_coordinatorlayout",
-        "androidx.core_core",
-        "androidx.fragment_fragment",
-        "androidx.lifecycle_lifecycle-runtime",
-        "androidx.loader_loader",
         "androidx.localbroadcastmanager_localbroadcastmanager",
-        "androidx.preference_preference",
-        "androidx.recyclerview_recyclerview",
-        "com.google.android.material_material",
-        "iconloader",
+        "androidx.room_room-runtime",
+        "zxing-core",
 
         "WifiTrackerLibRes",
+        "iconloader",
+        "setupdesign",
+
+        "SettingsLibActionBarShadow",
+        "SettingsLibActionButtonsPreference",
+        "SettingsLibAdaptiveIcon",
+        "SettingsLibAppPreference",
+        "SettingsLibBannerMessagePreference",
+        "SettingsLibBarChartPreference",
+        "SettingsLibButtonPreference",
+        "SettingsLibCollapsingToolbarBaseActivity",
         "SettingsLibDeviceStateRotationLock",
         "SettingsLibDisplayUtils",
         "SettingsLibEmergencyNumber",
+        "SettingsLibEntityHeaderWidgets",
+        "SettingsLibFooterPreference",
+        "SettingsLibHelpUtils",
+        "SettingsLibIllustrationPreference",
+        "SettingsLibLayoutPreference",
+        "SettingsLibMainSwitchPreference",
+        "SettingsLibProfileSelector",
+        "SettingsLibProgressBar",
+        "SettingsLibRestrictedLockUtils",
         "SettingsLibSearchWidget",
+        "SettingsLibSelectorWithWidgetPreference",
+        "SettingsLibSettingsSpinner",
+        "SettingsLibSettingsTransition",
+        "SettingsLibTopIntroPreference",
+        "SettingsLibTwoTargetPreference",
+        "SettingsLibUsageProgressBarPreference",
         "SettingsLibUtils",
-        "SettingsLibWidget",
-        "setupdesign",
-        "zxing-core-1.7",
-        "androidx.room_room-runtime",
         "settingslib_flags_lib",
     ],
 
@@ -47,56 +60,10 @@
     ],
 }
 
-// Group all the libraries with namespace "com.android.settingslib.widget", to allow SettingsLib to
-// set use_resource_processor = true.
-// We can remove SettingsLibWidget when all these libraries have its own namespace.
-android_library {
-    name: "SettingsLibWidget",
-    visibility: ["//visibility:private"],
-    manifest: "AndroidManifest-SettingsLibWidget.xml",
-    static_libs: [
-        "SettingsLibActionBarShadow",
-        "SettingsLibActionButtonsPreference",
-        "SettingsLibAdaptiveIcon",
-        "SettingsLibAppPreference",
-        "SettingsLibBannerMessagePreference",
-        "SettingsLibBarChartPreference",
-        "SettingsLibButtonPreference",
-        "SettingsLibCollapsingToolbarBaseActivity",
-        "SettingsLibEntityHeaderWidgets",
-        "SettingsLibFooterPreference",
-        "SettingsLibHelpUtils",
-        "SettingsLibIllustrationPreference",
-        "SettingsLibLayoutPreference",
-        "SettingsLibMainSwitchPreference",
-        "SettingsLibProfileSelector",
-        "SettingsLibProgressBar",
-        "SettingsLibRestrictedLockUtils",
-        "SettingsLibSelectorWithWidgetPreference",
-        "SettingsLibSettingsSpinner",
-        "SettingsLibSettingsTransition",
-        "SettingsLibTopIntroPreference",
-        "SettingsLibTwoTargetPreference",
-        "SettingsLibUsageProgressBarPreference",
-    ],
-
-    resource_dirs: [],
-}
-
 // NOTE: Keep this module in sync with ./common.mk
 java_defaults {
     name: "SettingsLibDefaults",
     static_libs: [
-        "androidx.annotation_annotation",
-        "androidx.appcompat_appcompat",
-        "androidx.coordinatorlayout_coordinatorlayout",
-        "androidx.core_core",
-        "androidx.fragment_fragment",
-        "androidx.lifecycle_lifecycle-runtime",
-        "androidx.loader_loader",
-        "androidx.localbroadcastmanager_localbroadcastmanager",
-        "androidx.preference_preference",
-        "androidx.recyclerview_recyclerview",
         "SettingsLib",
     ],
 }
diff --git a/packages/SettingsLib/AndroidManifest-SettingsLibWidget.xml b/packages/SettingsLib/AndroidManifest-SettingsLibWidget.xml
deleted file mode 100644
index 38a7d6a..0000000
--- a/packages/SettingsLib/AndroidManifest-SettingsLibWidget.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2023 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.
--->
-
-<manifest package="com.android.settingslib.widget" />
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index 33aa985..4871ef3 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -9,6 +9,7 @@
 
 android_library {
     name: "SettingsLibMainSwitchPreference",
+    use_resource_processor: true,
 
     srcs: ["src/**/*.java"],
     resource_dirs: ["res"],
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 56b3eac..6001155 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -31,12 +31,11 @@
 import androidx.annotation.ColorInt;
 
 import com.android.settingslib.utils.BuildCompatUtils;
+import com.android.settingslib.widget.mainswitch.R;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import com.android.settingslib.widget.mainswitch.R;
-
 /**
  * MainSwitchBar is a View with a customized Switch.
  * This component is used as the main switch of the page
@@ -77,7 +76,7 @@
             final TypedArray a = context.obtainStyledAttributes(
                     new int[]{android.R.attr.colorAccent});
             mBackgroundActivatedColor = a.getColor(0, 0);
-            mBackgroundColor = context.getColor(R.color.material_grey_600);
+            mBackgroundColor = context.getColor(androidx.appcompat.R.color.material_grey_600);
             a.recycle();
         }
 
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt
index 0552c40..1ad075c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt
@@ -31,7 +31,6 @@
 import androidx.compose.foundation.layout.width
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.Delete
-import androidx.compose.material.icons.outlined.Launch
 import androidx.compose.material.icons.outlined.WarningAmber
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.FilledTonalButton
@@ -52,6 +51,7 @@
 import com.android.settingslib.spa.framework.theme.SettingsShape
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.framework.theme.divider
+import androidx.compose.material.icons.automirrored.outlined.Launch
 
 data class ActionButton(
     val text: String,
@@ -101,7 +101,9 @@
                 modifier = Modifier.size(SettingsDimension.itemIconSize),
             )
             Box(
-                modifier = Modifier.padding(top = 4.dp).fillMaxHeight(),
+                modifier = Modifier
+                    .padding(top = 4.dp)
+                    .fillMaxHeight(),
                 contentAlignment = Alignment.Center,
             ) {
                 Text(
@@ -129,7 +131,7 @@
     SettingsTheme {
         ActionButtons(
             listOf(
-                ActionButton(text = "Open", imageVector = Icons.Outlined.Launch) {},
+                ActionButton(text = "Open", imageVector = Icons.AutoMirrored.Outlined.Launch) {},
                 ActionButton(text = "Uninstall", imageVector = Icons.Outlined.Delete) {},
                 ActionButton(text = "Force stop", imageVector = Icons.Outlined.WarningAmber) {},
             )
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt
index d0a6188..0757df3 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt
@@ -29,8 +29,8 @@
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.remember
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.testTag
@@ -46,6 +46,7 @@
 fun SettingsTextFieldPassword(
     value: String,
     label: String,
+    enabled: Boolean = true,
     onTextChange: (String) -> Unit,
 ) {
     var visibility by remember { mutableStateOf(false) }
@@ -60,6 +61,7 @@
             keyboardType = KeyboardType.Password,
             imeAction = ImeAction.Send
         ),
+        enabled = enabled,
         trailingIcon = {
             Icon(
                 imageVector = if (visibility) Icons.Outlined.VisibilityOff
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
index 62189dc..6ef4590 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
@@ -18,7 +18,6 @@
 
 import androidx.appcompat.R
 import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.outlined.ArrowBack
 import androidx.compose.material.icons.outlined.Clear
 import androidx.compose.material.icons.outlined.FindInPage
 import androidx.compose.material3.Icon
@@ -31,6 +30,7 @@
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.LayoutDirection
 import com.android.settingslib.spa.framework.compose.LocalNavController
+import androidx.compose.material.icons.automirrored.outlined.ArrowBack
 
 /** Action that navigates back to last page. */
 @Composable
@@ -53,7 +53,7 @@
 private fun BackAction(contentDescription: String, onClick: () -> Unit) {
     IconButton(onClick) {
         Icon(
-            imageVector = Icons.Outlined.ArrowBack,
+            imageVector = Icons.AutoMirrored.Outlined.ArrowBack,
             contentDescription = contentDescription,
             modifier = Modifier.autoMirrored(),
         )
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
index aa148b0..9f7f040 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
@@ -21,7 +21,7 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.pager.HorizontalPager
 import androidx.compose.foundation.pager.rememberPagerState
-import androidx.compose.material3.TabRow
+import androidx.compose.material3.PrimaryTabRow
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
@@ -43,7 +43,7 @@
         val coroutineScope = rememberCoroutineScope()
         val pagerState = rememberPagerState { titles.size }
 
-        TabRow(
+        PrimaryTabRow(
             selectedTabIndex = pagerState.currentPage,
             modifier = Modifier.padding(horizontal = SettingsDimension.itemPaddingEnd),
             containerColor = Color.Transparent,
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/button/ActionButtonsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/button/ActionButtonsTest.kt
index f59b0de..8d9bac6 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/button/ActionButtonsTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/button/ActionButtonsTest.kt
@@ -17,8 +17,8 @@
 package com.android.settingslib.spa.widget.button
 
 import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.outlined.Launch
 import androidx.compose.material.icons.outlined.Close
-import androidx.compose.material.icons.outlined.Launch
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
@@ -43,7 +43,10 @@
         composeTestRule.setContent {
             ActionButtons(
                 listOf(
-                    ActionButton(text = "Open", imageVector = Icons.Outlined.Launch) {},
+                    ActionButton(
+                        text = "Open",
+                        imageVector = Icons.AutoMirrored.Outlined.Launch
+                    ) {},
                 )
             )
         }
@@ -57,7 +60,7 @@
         composeTestRule.setContent {
             ActionButtons(
                 listOf(
-                    ActionButton(text = "Open", imageVector = Icons.Outlined.Launch) {
+                    ActionButton(text = "Open", imageVector = Icons.AutoMirrored.Outlined.Launch) {
                         clicked = true
                     },
                 )
@@ -74,7 +77,10 @@
         composeTestRule.setContent {
             ActionButtons(
                 listOf(
-                    ActionButton(text = "Open", imageVector = Icons.Outlined.Launch) {},
+                    ActionButton(
+                        text = "Open",
+                        imageVector = Icons.AutoMirrored.Outlined.Launch
+                    ) {},
                     ActionButton(text = "Close", imageVector = Icons.Outlined.Close) {},
                 )
             )
diff --git a/packages/SettingsLib/Spa/testutils/Android.bp b/packages/SettingsLib/Spa/testutils/Android.bp
index 4031cd7..639d1a7 100644
--- a/packages/SettingsLib/Spa/testutils/Android.bp
+++ b/packages/SettingsLib/Spa/testutils/Android.bp
@@ -31,7 +31,7 @@
         "androidx.compose.ui_ui-test-manifest",
         "androidx.lifecycle_lifecycle-runtime-testing",
         "mockito-kotlin2",
-        "truth-prebuilt",
+        "truth",
     ],
     kotlincflags: [
         "-Xjvm-default=all",
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
index dfd8f6b..3525037 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
@@ -18,8 +18,10 @@
 
 import android.app.admin.DevicePolicyManager
 import android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER
+import android.app.admin.DevicePolicyResources.Strings.Settings.PRIVATE_CATEGORY_HEADER
 import android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER
 import android.content.Context
+import android.content.pm.UserInfo
 import com.android.settingslib.R
 
 class EnterpriseRepository(private val context: Context) {
@@ -30,8 +32,10 @@
     fun getEnterpriseString(updatableStringId: String, resId: Int): String =
         checkNotNull(resources.getString(updatableStringId) { context.getString(resId) })
 
-    fun getProfileTitle(isManagedProfile: Boolean): String = if (isManagedProfile) {
+    fun getProfileTitle(userInfo: UserInfo): String = if (userInfo.isManagedProfile) {
         getEnterpriseString(WORK_CATEGORY_HEADER, R.string.category_work)
+    } else if (userInfo.isPrivateProfile) {
+        getEnterpriseString(PRIVATE_CATEGORY_HEADER, R.string.category_private)
     } else {
         getEnterpriseString(PERSONAL_CATEGORY_HEADER, R.string.category_personal)
     }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
index 6a76c93..5447f21 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
@@ -45,7 +45,7 @@
         val enterpriseRepository = EnterpriseRepository(context)
         userGroups.map { userGroup ->
             enterpriseRepository.getProfileTitle(
-                isManagedProfile = userGroup.userInfos.first().isManagedProfile,
+                userGroup.userInfos.first(),
             )
         }
     }
diff --git a/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig b/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig
index d1bcb57..4936f88 100644
--- a/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig
@@ -5,4 +5,11 @@
   namespace: "media_solutions"
   description: "Gates whether to use a MediaRouter2-based implementation of InfoMediaManager, instead of the legacy MediaRouter2Manager-based implementation."
   bug: "192657812"
+}
+
+flag {
+  name: "enable_tv_media_output_dialog"
+  namespace: "tv_system_ui"
+  description: "Gates all the changes for the tv specific media output dialog"
+  bug: "303205631"
 }
\ No newline at end of file
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index d959656..431fd44 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -18,18 +18,5 @@
 # to the corresponding module.
 # NOTE: keep this file and ./Android.bp in sync.
 
-LOCAL_STATIC_JAVA_LIBRARIES += \
-    androidx.annotation_annotation
-
 LOCAL_STATIC_ANDROID_LIBRARIES += \
-    androidx.appcompat_appcompat \
-    androidx.coordinatorlayout_coordinatorlayout \
-    androidx.core_core \
-    androidx.fragment_fragment \
-    androidx.lifecycle_lifecycle-runtime \
-    androidx.loader_loader \
-    androidx.localbroadcastmanager_localbroadcastmanager \
-    androidx.preference_preference \
-    androidx.recyclerview_recyclerview \
     SettingsLib
-
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 53db192..afdb92b 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi twee stawe."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi drie stawe."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi-sein vol."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Gekoppel aan jou toestel."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Oop netwerk"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Veilige netwerk"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android-bedryfstelsel"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 77c9a97..ea8491b 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ሁለት የWiFi አሞሌዎች።"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ሦስት የWiFi አሞሌዎች።"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"የWiFi ምልክት ሙሉ ነው።"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ከመሣሪያዎ ጋር ተገናኝቷል።"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"አውታረ መረብ ክፈት"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ደህንነቱ የተጠበቀ አውታረ መረብ"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android  ስርዓተ ክወና"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 30d011a..c29e691 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"‏إشارة Wi-Fi تتكون من شريطين."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"‏إشارة Wi-Fi تتكون من ثلاثة أشرطة."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"‏إشارة Wi-Fi كاملة."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"تم الاتصال بجهازك."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"شبكة مفتوحة"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"شبكة محمية بكلمة مرور"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"‏نظام التشغيل Android"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 31aff6a..8eff4f6 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ৱাই-ফাইৰ দুডাল দণ্ড।"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ৱাই-ফাইৰ তিনিডাল দণ্ড।"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ৱাই-ফাই সংকেত সৰ্বোচ্চ।"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"আপোনাৰ ডিভাইচটোৰ সৈতে সংযোগ কৰা আছে।"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"মুক্ত নেটৱৰ্ক"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"সুৰক্ষিত নেটৱৰ্ক"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index c675ce7..dfd1b7b 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi iki xətdir."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi üç xətdir."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi siqnalı tamdır."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Cihaza qoşuldu."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Açıq şəbəkə"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Təhlükəsiz şəbəkə"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index f7be60f..528e96e 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi signal ima dve crte."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi signal ima tri crte."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi signal je najjači."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Povezano je sa uređajem."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Otvorena mreža"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Bezbedna mreža"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index d2f2851..52614b7 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Два слупкi Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Тры слупкi Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Поўны сігнал Wi-Fi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Устаноўлена падключэнне да прылады."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Адкрытая сетка"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Бяспечная сетка"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"АС Android"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 2540c12..b28ae67 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi е с две чертички."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi е с три чертички."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Сигналът за Wi-Fi е пълен."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Установена е връзка с устройството ви."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Отворена мрежа"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Защитена мрежа"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android (ОС)"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 745b944..c91f14c 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ওয়াই ফাই এ দুইটি দণ্ড৷"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ওয়াই ফাই এ তিনটি দণ্ড৷"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ওয়াই ফাই এ সম্পূর্ণ সিগন্যাল৷"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"আপনার ডিভাইসের সাথে কানেক্ট করা হয়েছে।"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"খোলা নেটওয়ার্ক"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"সুরক্ষিত নেটওয়ার্ক"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index cab0841..aa1073d 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi signal ima dvije crte."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi signal ima tri crte."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi signal je pun."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Povezani ste s uređajem."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Otvorena mreža"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sigurna mreža"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index a65b9c2..ab6393a7 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Senyal Wi-Fi: dues barres."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Senyal Wi-Fi: tres barres."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Senyal Wi-Fi: complet."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"S\'ha connectat al teu dispositiu."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Xarxa oberta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Xarxa segura"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 96c02ae..e7d5243 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi – dvě čárky."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi – tři čárky."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi – plný signál."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Připojeno k vašemu zařízení."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Nezabezpečená síť"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Zabezpečená síť"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 1e4c7b7..1612ac0 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi har to bjælker."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi har tre bjælker."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi har fuldt signal."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Der er oprettet forbindelse til din enhed."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Åbent netværk"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sikkert netværk"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 37f7e5a..73a44f1 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WLAN: zwei Balken"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WLAN: drei Balken"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WLAN: volle Signalstärke"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Mit deinem Gerät verbunden."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Offenes Netzwerk"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sicheres Netzwerk"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 84b8bf2..7dfd679 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Δύο γραμμές Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Τρεις γραμμές Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Άριστο σήμα Wi-Fi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Συνδέθηκε στη συσκευή σας."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Ανοικτό δίκτυο"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Ασφαλές δίκτυο"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Λειτουργικό σύστημα Android"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 7298c02..aead40d 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi two bars."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi three bars."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi signal full."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connected to your device."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Open network"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Secure network"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 7298c02..aead40d 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi two bars."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi three bars."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi signal full."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connected to your device."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Open network"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Secure network"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 7298c02..aead40d 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi two bars."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi three bars."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi signal full."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connected to your device."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Open network"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Secure network"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 86541fd..291a68b 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dos barras de Wi-Fi"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tres barras de Wi-Fi"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Señal de Wi-Fi excelente"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Se estableció conexión con el dispositivo."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Red abierta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Red segura"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"SO Android"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index ef9cc03..b4bc319 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dos barras de Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tres barras de Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Señal de Wi-Fi al máximo."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conectado a tu dispositivo."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Red abierta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Red segura"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"SO Android"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index c8d806b..e5cbaf6 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi: kaks pulka."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi: kolm pulka."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi-signaal on tugev."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Seadmega ühendatud."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Avatud võrk"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Turvaline võrk"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index 95adf96..00f43a3 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -264,7 +264,7 @@
   <string-array name="debug_hw_overdraw_entries">
     <item msgid="1968128556747588800">"Desaktibatuta"</item>
     <item msgid="3033215374382962216">"Erakutsi gainidatzi diren eremuak"</item>
-    <item msgid="3474333938380896988">"Erakutsi daltonismorako eremuak"</item>
+    <item msgid="3474333938380896988">"Erakutsi deuteranomaliarako eremuak"</item>
   </string-array>
   <string-array name="app_process_limit_entries">
     <item msgid="794656271086646068">"Muga estandarra"</item>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 7d76514..90d45eb 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi sarearen bi barra."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi sarearen hiru barra."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi sarearen seinalea osoa."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Gailura konektatuta."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Sare irekia"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sare segurua"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android sistema eragilea"</string>
@@ -368,7 +367,7 @@
     <string name="debug_hw_overdraw" msgid="8944851091008756796">"Araztu GPU gainidazketa"</string>
     <string name="disable_overlays" msgid="4206590799671557143">"Desgaitu HW gainjartzeak"</string>
     <string name="disable_overlays_summary" msgid="1954852414363338166">"Erabili beti GPUa pantaila-muntaietarako"</string>
-    <string name="simulate_color_space" msgid="1206503300335835151">"Simulatu kolore-eremua"</string>
+    <string name="simulate_color_space" msgid="1206503300335835151">"Simulatu kolore-espazioa"</string>
     <string name="enable_opengl_traces_title" msgid="4638773318659125196">"Gaitu OpenGL aztarnak"</string>
     <string name="usb_audio_disable_routing" msgid="3367656923544254975">"Desgaitu USB bidez audioa bideratzeko aukera"</string>
     <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Desgaitu USB bidezko audio-gailuetara automatikoki bideratzeko aukera"</string>
@@ -441,7 +440,7 @@
     <string name="picture_color_mode_desc" msgid="151780973768136200">"Erabili sRGB"</string>
     <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desgaituta"</string>
     <string name="daltonizer_mode_monochromacy" msgid="362060873835885014">"Ikusmen-monokromia"</string>
-    <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Daltonismoa (gorri-berdeak)"</string>
+    <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Deuteranomalia (gorri-berdeak)"</string>
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopia (gorri-berdeak)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (urdin-horia)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koloreen zuzenketa"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index beb0b96..f3f97c4 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"‏دو نوار برای Wi‑Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"‏سه نوار برای Wi‑Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"‏قدرت سیگنال Wi‑Fi کامل است."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"به دستگاهتان متصل شد."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"شبکه باز"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"شبکه ایمن"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"‏سیستم‌عامل Android"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 8872316..7f3d0f2 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi-signaali – kaksi palkkia"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi-signaali – kolme palkkia"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Vahva Wi-Fi-signaali"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Yhdistetty laitteeseesi."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Avoin verkko"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Suojattu verkko"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android-käyttöjärjestelmä"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 98e3753..b7c3a81 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi : deux barres."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi : trois barres."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi : signal complet."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connecté à votre appareil."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Réseau ouvert"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Réseau sécurisé"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Système d\'exploitation Android"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 4a64041..a9e0c6a 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Signal Wi-Fi moyen"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Signal Wi-Fi bon"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Signal Wi-Fi excellent"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connecté à votre appareil."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Réseau ouvert"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Réseau sécurisé"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 26738e6..09c2969 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dúas barras de wifi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tres barras de wifi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinal completo de wifi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conexión establecida co teu dispositivo."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rede aberta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rede segura"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"SO Android"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index b620d41..575c675 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi બે બાર."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi ત્રણ બાર."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"પૂર્ણ Wifi સિગ્નલ."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"તમારા ડિવાઇસ સાથે કનેક્ટેડ છે."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"નેટવર્ક ખોલો"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"સુરક્ષિત નેટવર્ક"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 3811167..655fac0 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"वाई-फ़ाई की दो पट्टी मिल रही हैं."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"वाई-फ़ाई की एक पट्टी मिल रही है."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"पूरे वाई-फ़ाई सिग्नल मिल रहे हैं."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"आपके डिवाइस से कनेक्ट हो गया है."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"खुला नेटवर्क"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"सुरक्षित नेटवर्क"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
@@ -598,7 +597,7 @@
     <string name="profile_info_settings_title" msgid="105699672534365099">"प्रोफ़ाइल की जानकारी"</string>
     <string name="user_need_lock_message" msgid="4311424336209509301">"इससे पहले कि आप कोई प्रतिबंधित प्रोफ़ाइल बनाएं, आपको अपने ऐप्लिकेशन  और व्यक्तिगत डेटा की सुरक्षा करने के लिए एक स्क्रीन लॉक सेट करना होगा."</string>
     <string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करें"</string>
-    <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> पर जाएं"</string>
+    <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> पर स्विच करें"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नए उपयोगकर्ता को जोड़ा जा रहा है…"</string>
     <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"नया मेहमान खाता बनाया जा रहा है…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"नया उपयोगकर्ता जोड़ा नहीं जा सका"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 71a2dae..f0e16a4 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi signal ima dva stupca."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi signal ima tri stupca."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi signal je pun."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Povezano s vašim uređajem."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Otvorena mreža"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sigurna mreža"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
@@ -619,7 +618,7 @@
     <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Time će se izbrisati aplikacije i podaci iz trenutačne gostujuće sesije."</string>
     <string name="grant_admin" msgid="4323199171790522574">"Da, dodijeli status administratora"</string>
     <string name="not_grant_admin" msgid="3557849576157702485">"Ne, nemoj dodijeliti status administratora"</string>
-    <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Izlaz"</string>
+    <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Izađi"</string>
     <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Želite li spremiti aktivnosti gosta?"</string>
     <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Možete spremiti aktivnosti iz ove sesije ili izbrisati sve aplikacije i podatke"</string>
     <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Izbriši"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 5fac75d..420e0e9 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi-jel: két sáv."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi-jel: három sáv."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi-jel: teljes."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Csatlakoztatva az eszközhöz."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Nyílt hálózat"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Biztonságos hálózat"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index e40c5e1..705fcf6 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi-ի ուժգնությունը՝ երկու գիծ:"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi-ի ուժգնությունը՝ երեք գիծ:"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi-ի ազդանշանը ուժեղ է:"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Միացած է ձեր սարքին։"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Բաց ցանց"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Անվտանգ ցանց"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index ca1b6be..e33dd05 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi dua baris"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi tiga baris."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinyal Wi-Fi penuh."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Terhubung ke perangkat Anda."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Jaringan terbuka"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Jaringan aman"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 1f2dcfb..e1fb248 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: Tvö strik."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: Þrjú strik."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Fullur Wi-Fi sendistyrkur."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Tengt við tækið þitt."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Opið net"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Öruggt net"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android stýrikerfið"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index e255c85..b2cfd37 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: due barre."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: tre barre."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Segnale Wi-Fi completo."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Connessione al dispositivo effettuata."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rete aperta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rete protetta"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Sistema operativo Android"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index edcac10..9ca7477 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"‏שני פסים של Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"‏שלושה פסים של Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"‏אות Wi-Fi מלא."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"מחובר למכשיר שלך."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"רשת פתוחה"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"רשת מאובטחת"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index bf21de2..dcce2b4 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fiはレベル2です。"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fiはレベル3です。"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fiの電波はフルです。"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"デバイスに接続しました。"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"オープンネットワーク"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"保護されたネットワーク"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 9000de4..eb32e1c 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi სიგნალი ორ ზოლზეა."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi სიგნალი სამ ზოლზეა."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi სიგნალი სრულია."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"დაკავშირებულია თქვენს მოწყობილობასთან."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ღია ქსელი"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"დაცული ქსელი"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 610fed1..73a8efd 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi сигналы — екі жолақ."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi сигналы — үш жолақ."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi сигналы толық."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Құрылғыңызға жалғанды."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Ашық желі"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Қауіпсіз желі"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index b7999c7..1c32e62 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi ពីរកាំ"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi បីកាំ"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"សេវា Wifi ពេញ"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"បានភ្ជាប់ទៅឧបករណ៍របស់អ្នក។"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"បើក​បណ្ដាញ"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"បណ្តាញ​ដែល​មានសុវត្ថិភាព"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"ប្រព័ន្ធ​ប្រតិបត្តិការ Android"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index c788dd5..ede347d 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ವೈಫೈ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ವೈಫೈ ಮೂರು ಪಟ್ಟಿಗಳು."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ವೈಫೈ ಸಿಗ್ನಲ್‌‌ ಪೂರ್ತಿ ಇದೆ."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ನೆಟ್‌ವರ್ಕ್‌ ತೆರೆಯಿರಿ"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ಸುರಕ್ಷಿತ ನೆಟ್‌ವರ್ಕ್"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 2c51d1f..78bd616 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi 신호 막대가 두 개입니다."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi 신호 막대가 세 개입니다."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi 신호가 강합니다."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"기기에 연결되었습니다."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"개방형 네트워크"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"보안 네트워크"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 14814f4..a0b9123 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi: эки таякча."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi: үч таякча."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi: күчтүү сигнал."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Түзмөгүңүзгө туташты."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Ачык тармак"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Коопсуз тармак"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 6430a98..96b2dc1 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ສັນຍານ Wi-Fi ສອງຂີດ."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi ສາມຂີດ."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ສັນຍານ Wi-Fi ເຕັມ"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ເຊື່ອມຕໍ່ກັບອຸປະກອນຂອງທ່ານແລ້ວ."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ເຄືອຂ່າຍເປີດ"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ເຄືອຂ່າຍເຂົ້າລະຫັດ"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 3642a90..69630f4 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dvi „Wi-Fi“ signalo juostos."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Trys „Wi-Fi“ signalo juostos."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Stiprus „Wi-Fi“ signalas."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Prisijungta prie įrenginio."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Atviras tinklas"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Saugus tinklas"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"„Android“ OS"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index c3163b8..4f76cee 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: divas joslas"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: trīs joslas"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Pilna piekļuve Wi-Fi signālam"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Izveidots savienojums ar ierīci."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Atvērts tīkls"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Drošs tīkls"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 017fed7..1c80c65 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Две црти на Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Три црти на Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Полн сигнал на Wi-Fi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Поврзано со уредот."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Отворена мрежа"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Заклучена мрежа"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Оперативен систем Android"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 3ef3f63..31e3c83 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"വൈഫൈ സിഗ്നൽ രണ്ട് ബാറുകൾ."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"വൈഫൈ സിഗ്നൽ മൂന്ന് ബാറുകൾ."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"വൈഫൈ മികച്ച സിഗ്‌നൽ."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"നിങ്ങളുടെ ഉപകരണത്തിലേക്ക് കണക്റ്റ് ചെയ്തു."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ഓപ്പൺ നെറ്റ്‍വര്‍ക്ക്"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"സുരക്ഷിത നെറ്റ്‍വര്‍ക്ക്"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index ccd1d41..5a636d9 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi сүлжээний дохио хоёр баганатай байна."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi сүлжээний дохио гурван баганатай байна."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi-н дохио дүүрэн байна."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Таны төхөөрөмжид холбогдсон."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Нээлттэй сүлжээ"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Аюулгүй сүлжээ"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Андройд OS"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index a34a9d3..4d78e57 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"वाय-फाय दोन बार."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"वाय-फाय तीन बार."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"वाय-फाय सिग्नल संपूर्ण आहे."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"तुमच्या डिव्हाइसशी कनेक्ट केले आहे."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"नेटवर्क उघडा"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"सुरक्षित नेटवर्क"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index b7d2734..2ae69bd 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi dua bar."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi tiga bar."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Isyarat Wi-Fi penuh."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Disambungkan kepada peranti anda."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rangkaian terbuka"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rangkaian selamat"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 0e43f65..7d6f2a7 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi  ၂ ဘား"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi  ၃ ဘား"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi  အပြည့်ရှိ"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"သင့်စက်သို့ ချိတ်ဆက်ထားသည်။"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"အများသုံး ကွန်ရက်"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"လုံခြုံသည့် ကွန်ရက်"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 43824c3..9e550fb 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi-signal med to stolper."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi-signal med tre stolper."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi-signalet er ved full styrke."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Koblet til enheten."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Åpent nettverk"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sikkert nettverk"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android-operativsystem"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index e879849..1f6ad5b 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi दुई पट्टि।"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi तीन बारहरू।"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"पूर्ण Wi-Fi सिंग्नल।"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"तपाईंको डिभाइसमा कनेक्ट गरिएको छ।"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"खुला नेटवर्क"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"सुरक्षित नेटवर्क"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index dedacff..6a6f184 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi: twee streepjes."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi: drie streepjes."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifii-signaal is op volledige sterkte."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Verbonden met je apparaat."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Open netwerk"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Beveiligd netwerk"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android-besturingssysteem"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index cbd9ffd..980a374 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"ୱାଇ-ଫାଇର ଦୁଇଟି ବାର୍‌ ଅଛି।"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"ୱାଇ-ଫାଇର ତିନୋଟି ବାର୍।"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"ୱାଇ-ଫାଇର ସଙ୍କେତ ସର୍ବୋଚ୍ଚ।"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ଆପଣଙ୍କ ଡିଭାଇସ ସହ କନେକ୍ଟ କରାଯାଇଛି।"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ଖୋଲା ନେଟୱର୍କ"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ସୁରକ୍ଷିତ ନେଟ୍‌ୱର୍କ"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index e4814ac..dd3fa15 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi ਦੋ ਬਾਰ।"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi ਤਿੰਨ ਬਾਰ।"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi ਸਿਗਨਲ ਪੂਰਾ।"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ਖੁੱਲ੍ਹਾ ਨੈੱਟਵਰਕ"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ਸੁਰੱਖਿਅਤ ਨੈੱਟਵਰਕ"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index f5dc9cc..f4ebd29 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: dwa paski."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: trzy paski."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi: pełna moc sygnału."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Połączono z urządzeniem."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Sieć otwarta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sieć zabezpieczona"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"System operacyjny Android"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 4e96bc6..bb6c7d8 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Duas barras de Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Três barras de Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinal Wi-Fi cheio."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conectado ao dispositivo."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rede aberta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rede segura"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Sistema operacional Android"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 0c4abdb..6bd5c2a 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Duas barras de Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Três barras de Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinal de Wi-Fi completo."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Com ligação ao dispositivo."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rede aberta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rede segura"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"SO Android"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 4e96bc6..bb6c7d8 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Duas barras de Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Três barras de Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Sinal Wi-Fi cheio."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conectado ao dispositivo."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rede aberta"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rede segura"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Sistema operacional Android"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 529a6c6..f4399dc 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Semnal Wi-Fi: două bare."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Semnal Wi-Fi: trei bare."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Semnal Wi-Fi: complet."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Conectată la dispozitiv."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rețea nesecurizată"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Securizează rețeaua"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Sistem de operare Android"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 87a81ee..5d45e29 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: два деления"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: три деления"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi: надежный сигнал"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Подключено к точке доступа на вашем устройстве."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Открытая сеть"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Защищенная сеть"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"ОС Android"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 9015a42..996507d 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi තීරු දෙකයි."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi තීරු තුනයි."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi සංඥාව පිරී ඇත."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"ඔබේ උපාංගයට සම්බන්ධයි."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"විවෘත ජාලය"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"ආරක්ෂිත ජාලය"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 8c6bf4f..a51acd4 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dve čiarky signálu Wi‑Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tri čiarky signálu Wi‑Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Plný signál Wi‑Fi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Pripojené k vášmu zariadeniu."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Otvorená sieť"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Zabezpečená sieť"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index cc19abe..0d7188d 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Dve črtici signala Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tri črtice signala Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Poln signal Wi-Fi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Povezava z napravo je vzpostavljena."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Odprto omrežje"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Varno omrežje"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"OS Android"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 43a2c4c..c2bcce7 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi ka dy vija."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: tre vija."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi ka sinjal të plotë."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Lidhur me pajisjen tënde"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Rrjet i hapur"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Rrjet i sigurt"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Sistemi operativ Android"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 00a98bc..09ff994 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WiFi сигнал има две црте."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WiFi сигнал има три црте."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WiFi сигнал је најјачи."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Повезано је са уређајем."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Отворена мрежа"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Безбедна мрежа"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android ОС"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 01b462d..fdd9d8c 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi: två staplar."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi: tre staplar."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Full signalstyrka för wifi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Ansluten till enheten."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Öppet nätverk"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Säkert nätverk"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Operativsystemet Android"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 9453e5f..bd41752 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Vipima mtandao viwili vya Wifi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Vipima mtandao vitatu vya Wifi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Nguvu kamili ya mtandao wa Wifi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Imeunganishwa kwenye kifaa chako."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Mtandao unaotumiwa na mtu yeyote"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Mtandao salama"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Mfumo wa Uendeshaji wa Android"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 836b4da..fd379f0 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"வைஃபை சிக்னல்: இரண்டு கோடுகள்."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"வைஃபை சிக்னல்: மூன்று கோடுகள்."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"வைஃபை சிக்னல் முழுமையாக உள்ளது."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"உங்கள் சாதனத்துடன் இணைக்கப்பட்டது."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"கடவுச்சொல் தேவைப்படாத திறந்த நெட்வொர்க்"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"கடவுச்சொல் தேவைப்படும் பாதுகாப்பான நெட்வொர்க்"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 34b8264..3e9d8be 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi సిగ్నల్ రెండు బార్‌లు ఉంది."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi సిగ్నల్ మూడు బార్‌లు ఉంది."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi సిగ్నల్ పూర్తిగా ఉంది."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"మీ పరికరానికి కనెక్ట్ చేయబడింది."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"ఓపెన్ నెట్‌వర్క్"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"సురక్షిత నెట్‌వర్క్"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index da3a5c5..e67f371 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"สัญญาณ Wi-Fi 2 ขีด"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"สัญญาณ Wi-Fi 3 ขีด"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"สัญญาณ Wi-Fi เต็ม"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"เชื่อมต่อกับอุปกรณ์แล้ว"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"เครือข่ายแบบเปิด"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"เครือข่ายที่ปลอดภัย"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"ระบบปฏิบัติการ Android"</string>
@@ -598,7 +597,7 @@
     <string name="profile_info_settings_title" msgid="105699672534365099">"ข้อมูลโปรไฟล์"</string>
     <string name="user_need_lock_message" msgid="4311424336209509301">"ก่อนที่คุณจะสามารถสร้างโปรไฟล์ที่ถูกจำกัดได้ คุณจะต้องตั้งค่าล็อกหน้าจอเพื่อปกป้องแอปและข้อมูลส่วนตัวของคุณ"</string>
     <string name="user_set_lock_button" msgid="1427128184982594856">"ตั้งค่าล็อก"</string>
-    <string name="user_switch_to_user" msgid="6975428297154968543">"เปลี่ยนเป็น <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+    <string name="user_switch_to_user" msgid="6975428297154968543">"เปลี่ยนเป็น<xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"กำลังสร้างผู้ใช้ใหม่…"</string>
     <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"กำลังสร้างผู้ใช้ชั่วคราวใหม่…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"สร้างผู้ใช้ใหม่ไม่ได้"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index f6d2256..440bbe7 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"May dalawang bar ang Wifi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"May tatlong bar ang Wifi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Puno ang signal ng Wifi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Nakakonekta sa iyong device."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Bukas na network"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Ligtas na network"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index acd3d00e..b38012f 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Kablosuz sinyal gücü iki çubuk."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Kablosuz sinyal gücü üç çubuk."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Kablosuz sinyal gücü tam."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Cihazınıza bağlandı."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Açık ağ"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Güvenli ağ"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index dd5898a..4f08547 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Дві смужки сигналу Wi-Fi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Три смужки сигналу Wi-Fi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Максимальний сигнал Wi-Fi."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Підключено до пристрою."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Відкрита мережа"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Захищена мережа"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"ОС Android"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 182bd04..ce67d15 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"‏Wifi دو بارز۔"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"‏Wifi تین بارز۔"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"‏Wifi سگنل پورا ہے۔"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"آپ کے آلے سے منسلک ہے۔"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"اوپن نیٹ ورک"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"محفوظ نیٹ ورک"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index b831a4b..77da981 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi: ikkita ustun"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi: uchta ustun"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi: signal to‘liq"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Qurilmaga ulandi."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Ochiq tarmoq"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Xavfsiz tarmoq"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android OS"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 3e94593..bf510f6 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Tín hiệu Wi-Fi hai vạch."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Tín hiệu Wi-Fi ba vạch."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Tín hiệu Wi-Fi đủ."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Đã kết nối với thiết bị của bạn."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Mạng mở"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Mạng bảo mật"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Hệ điều hành Android"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 53389c7..8e3145a 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"WLAN 信号强度为两格。"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"WLAN 信号强度为三格。"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"WLAN 信号满格。"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"已连接到您的设备。"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"开放网络"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"安全网络"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android 操作系统"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index daedba6..aa9f21f 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi 訊號兩格。"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi 訊號三格。"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi 訊號滿格。"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"已連接裝置。"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"開放式網絡"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"安全網絡"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android 作業系統"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 94ebd98..3c65a4d 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi 訊號強度兩格。"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi 訊號強度三格。"</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi 訊號強度滿格。"</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"已連上裝置。"</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"開放式網路"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"安全網路"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android 作業系統"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 92a4b81..08b04cc 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -157,8 +157,7 @@
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Amabha amabili we-Wifi."</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Amabha amathathu we-Wifi."</string>
     <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Isiginali ye-Wifi igcwele."</string>
-    <!-- no translation found for accessibility_wifi_other_device (2815627624555795918) -->
-    <skip />
+    <string name="accessibility_wifi_other_device" msgid="2815627624555795918">"Ixhume kudivayisi yakho."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Vula inethiwekhi"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Inethiwekhi evikelekile"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"I-Android OS"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 49bd9d9..9687674 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -518,6 +518,8 @@
     <string name="category_personal">Personal</string>
     <!-- Header for items under the work user [CHAR LIMIT=30] -->
     <string name="category_work">Work</string>
+    <!-- Header for items under the private profile user [CHAR LIMIT=30] -->
+    <string name="category_private">Private</string>
     <!-- Header for items under the clone user [CHAR LIMIT=30] -->
     <string name="category_clone">Clone</string>
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSimStatusImeiInfoPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSimStatusImeiInfoPreferenceController.java
deleted file mode 100644
index a78440c..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSimStatusImeiInfoPreferenceController.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 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.settingslib.deviceinfo;
-
-import android.content.Context;
-import android.os.UserManager;
-
-import com.android.settingslib.Utils;
-import com.android.settingslib.core.AbstractPreferenceController;
-
-public abstract class AbstractSimStatusImeiInfoPreferenceController
-        extends AbstractPreferenceController {
-    public AbstractSimStatusImeiInfoPreferenceController(Context context) {
-        super(context);
-    }
-
-    @Override
-    public boolean isAvailable() {
-        return mContext.getSystemService(UserManager.class).isAdminUser()
-                && !Utils.isWifiOnly(mContext);
-    }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/SupervisedDeviceActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/SupervisedDeviceActionDisabledByAdminController.java
index 815293e9..09f34b3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/SupervisedDeviceActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/SupervisedDeviceActionDisabledByAdminController.java
@@ -16,17 +16,20 @@
 
 package com.android.settingslib.enterprise;
 
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.net.Uri;
 import android.provider.Settings;
-import android.util.Log;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.settingslib.RestrictedLockUtils;
 
-import org.jetbrains.annotations.Nullable;
 
 final class SupervisedDeviceActionDisabledByAdminController
         extends BaseActionDisabledByAdminController {
@@ -57,8 +60,13 @@
 
     @Nullable
     @Override
-    public DialogInterface.OnClickListener getPositiveButtonListener(Context context,
-            RestrictedLockUtils.EnforcedAdmin enforcedAdmin) {
+    public DialogInterface.OnClickListener getPositiveButtonListener(@NonNull Context context,
+            @NonNull RestrictedLockUtils.EnforcedAdmin enforcedAdmin) {
+        if (enforcedAdmin.component == null
+                || TextUtils.isEmpty(enforcedAdmin.component.getPackageName())) {
+            return null;
+        }
+
         final Intent intent = new Intent(Settings.ACTION_MANAGE_SUPERVISOR_RESTRICTED_SETTING)
                 .setData(new Uri.Builder()
                         .scheme("policy")
@@ -72,7 +80,6 @@
             return null;
         }
         return (dialog, which) -> {
-            Log.d(TAG, "Positive button clicked, component: " + enforcedAdmin.component);
             context.startActivity(intent);
         };
     }
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index b03c43c..4b4caf5 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -52,7 +52,7 @@
         "flag-junit",
         "mockito-target-minus-junit4",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
         "SettingsLibDeviceStateRotationLock",
         "SettingsLibSettingsSpinner",
         "SettingsLibUsageProgressBarPreference",
diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp
index dd9cb9c..2d875cf 100644
--- a/packages/SettingsLib/tests/robotests/Android.bp
+++ b/packages/SettingsLib/tests/robotests/Android.bp
@@ -96,6 +96,6 @@
     libs: [
         "Robolectric_all-target_upstream",
         "mockito-robolectric-prebuilt",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayoutTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayoutTest.java
index 2b1e808..507dcbc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayoutTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayoutTest.java
@@ -55,8 +55,7 @@
     @Test
     public void onCreate_userAddedChildViewsBeMovedToContentFrame() {
         CollapsingCoordinatorLayout layout = mActivity.getCollapsingCoordinatorLayout();
-        View contentFrameView =
-                layout.findViewById(com.android.settingslib.widget.R.id.content_frame);
+        View contentFrameView = layout.findViewById(R.id.content_frame);
 
         TextView textView = contentFrameView.findViewById(com.android.settingslib.robotests.R.id.text_hello_world);
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
deleted file mode 100644
index 52d243a..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2017 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.settingslib.deviceinfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.robolectric.shadow.api.Shadow.extract;
-
-import android.os.UserManager;
-import android.telephony.TelephonyManager;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {SimStatusImeiInfoPreferenceControllerTest.ShadowUserManager.class,
-                SimStatusImeiInfoPreferenceControllerTest.ShadowTelephonyManager.class})
-public class SimStatusImeiInfoPreferenceControllerTest {
-
-    private AbstractSimStatusImeiInfoPreferenceController mController;
-
-    @Before
-    public void setUp() {
-        mController = new AbstractSimStatusImeiInfoPreferenceController(
-                RuntimeEnvironment.application) {
-            @Override
-            public String getPreferenceKey() {
-                return null;
-            }
-        };
-    }
-
-    @Test
-    public void testIsAvailable_isAdminAndHasMobile_shouldReturnTrue() {
-        ShadowUserManager userManager =
-                extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
-        userManager.setIsAdminUser(true);
-        ShadowTelephonyManager telephonyManager =
-                extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class));
-        telephonyManager.setDataCapable(true);
-
-        assertThat(mController.isAvailable()).isTrue();
-    }
-
-    @Test
-    public void testIsAvailable_isAdminButNoMobile_shouldReturnFalse() {
-        ShadowUserManager userManager =
-                extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
-        userManager.setIsAdminUser(true);
-        ShadowTelephonyManager telephonyManager =
-                extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class));
-        telephonyManager.setDataCapable(false);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void testIsAvailable_isNotAdmin_shouldReturnFalse() {
-        ShadowUserManager userManager =
-                extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
-        userManager.setIsAdminUser(false);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Implements(UserManager.class)
-    public static class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
-
-        private boolean mAdminUser;
-
-        public void setIsAdminUser(boolean isAdminUser) {
-            mAdminUser = isAdminUser;
-        }
-
-        @Implementation
-        public boolean isAdminUser() {
-            return mAdminUser;
-        }
-    }
-
-    @Implements(TelephonyManager.class)
-    public static class ShadowTelephonyManager
-            extends org.robolectric.shadows.ShadowTelephonyManager {
-        private boolean mDataCapable = false;
-        private void setDataCapable(boolean capable) {
-            mDataCapable = capable;
-        }
-
-        @Implementation
-        public boolean isDataCapable() {
-            return mDataCapable;
-        }
-    }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveIconTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveIconTest.java
index 6195d75..71545b7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveIconTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveIconTest.java
@@ -36,10 +36,10 @@
 import android.graphics.drawable.ShapeDrawable;
 import android.os.Bundle;
 
-import com.android.settingslib.widget.adaptiveicon.R;
 import com.android.settingslib.drawer.ActivityTile;
 import com.android.settingslib.drawer.CategoryKey;
 import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.widget.adaptiveicon.R;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -105,15 +105,15 @@
 
         icon.setBackgroundColor(mContext, tile);
 
-        assertThat(icon.mBackgroundColor).isEqualTo(mContext.getColor(
-                com.android.settingslib.widget.R.color.homepage_generic_icon_background));
+        assertThat(icon.mBackgroundColor).isEqualTo(
+                mContext.getColor(R.color.homepage_generic_icon_background));
     }
 
     @Test
     public void onBindTile_externalTileWithBackgroundColorHint_shouldUpdateIcon() {
         final Tile tile = spy(new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
         mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON_BACKGROUND_HINT,
-                com.android.settingslib.widget.R.color.bt_outline_color);
+                R.color.bt_outline_color);
         doReturn(Icon.createWithResource(mContext, com.android.settingslib.R.drawable.ic_system_update))
                 .when(tile).getIcon(mContext);
 
@@ -121,8 +121,7 @@
                 new AdaptiveIcon(mContext, new ColorDrawable(Color.BLACK));
         icon.setBackgroundColor(mContext, tile);
 
-        assertThat(icon.mBackgroundColor).isEqualTo(mContext.getColor(
-                com.android.settingslib.widget.R.color.bt_outline_color));
+        assertThat(icon.mBackgroundColor).isEqualTo(mContext.getColor(R.color.bt_outline_color));
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
index ccbe4f0..0ce83c6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
@@ -58,16 +58,14 @@
     @Test
     public void setLearnMoreText_shouldSetAsTextInLearnMore() {
         final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext)
-                        .inflate(com.android.settingslib.widget.R.layout.preference_footer, null));
+                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null));
         mFooterPreference.setLearnMoreText("Custom learn more");
         mFooterPreference.setLearnMoreAction(view -> { /* do nothing */ } /* listener */);
 
         mFooterPreference.onBindViewHolder(holder);
 
-        assertThat(((TextView) holder.findViewById(
-                com.android.settingslib.widget.R.id.settingslib_learn_more)).getText().toString())
-                .isEqualTo("Custom learn more");
+        TextView learnMoreView = (TextView) holder.findViewById(R.id.settingslib_learn_more);
+        assertThat(learnMoreView.getText().toString()).isEqualTo("Custom learn more");
     }
 
     @Test
@@ -95,8 +93,7 @@
     @Test
     public void onBindViewHolder_whenTitleIsNull_shouldNotRaiseNpe() {
         PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext)
-                        .inflate(R.layout.preference_footer, null)));
+                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null)));
         when(viewHolder.findViewById(androidx.core.R.id.title)).thenReturn(null);
 
         Throwable actualThrowable = null;
@@ -112,10 +109,8 @@
     @Test
     public void onBindViewHolder_whenLearnMoreIsNull_shouldNotRaiseNpe() {
         PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext)
-                        .inflate(com.android.settingslib.widget.R.layout.preference_footer, null)));
-        when(viewHolder.findViewById(com.android.settingslib.widget.R.id.settingslib_learn_more))
-                .thenReturn(null);
+                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null)));
+        when(viewHolder.findViewById(R.id.settingslib_learn_more)).thenReturn(null);
 
         Throwable actualThrowable = null;
         try {
@@ -130,8 +125,7 @@
     @Test
     public void onBindViewHolder_whenIconFrameIsNull_shouldNotRaiseNpe() {
         PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext)
-                        .inflate(com.android.settingslib.widget.R.layout.preference_footer, null)));
+                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null)));
         when(viewHolder.findViewById(R.id.icon_frame)).thenReturn(null);
 
         Throwable actualThrowable = null;
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
deleted file mode 100644
index 0b9ba8d..0000000
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2018 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.settingslib.testutils.shadow;
-
-import static android.os.Build.VERSION_CODES.O;
-
-import android.app.ActivityManager;
-import android.app.IActivityManager;
-
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.Resetter;
-import org.robolectric.shadow.api.Shadow;
-import org.robolectric.util.ReflectionHelpers;
-
-@Implements(ActivityManager.class)
-public class ShadowActivityManager {
-    private static int sCurrentUserId = 0;
-    private static int sUserSwitchedTo = -1;
-
-    @Resetter
-    public static void reset() {
-        sCurrentUserId = 0;
-        sUserSwitchedTo = 0;
-    }
-
-    @Implementation
-    protected static int getCurrentUser() {
-        return sCurrentUserId;
-    }
-
-    @Implementation
-    protected boolean switchUser(int userId) {
-        sUserSwitchedTo = userId;
-        return true;
-    }
-
-    @Implementation(minSdk = O)
-    protected static IActivityManager getService() {
-        return ReflectionHelpers.createNullProxy(IActivityManager.class);
-    }
-
-    public boolean getSwitchUserCalled() {
-        return sUserSwitchedTo != -1;
-    }
-
-    public int getUserSwitchedTo() {
-        return sUserSwitchedTo;
-    }
-
-    public static void setCurrentUser(int userId) {
-        sCurrentUserId = userId;
-    }
-
-    public static ShadowActivityManager getShadow() {
-        return (ShadowActivityManager) Shadow.extract(
-                RuntimeEnvironment.application.getSystemService(ActivityManager.class));
-    }
-}
diff --git a/packages/SettingsLib/tests/unit/Android.bp b/packages/SettingsLib/tests/unit/Android.bp
index 19ab1c6..6d6e2ff 100644
--- a/packages/SettingsLib/tests/unit/Android.bp
+++ b/packages/SettingsLib/tests/unit/Android.bp
@@ -31,6 +31,6 @@
         "SettingsLib",
         "androidx.test.ext.junit",
         "androidx.test.runner",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 92ebe09..f4ca260 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -64,7 +64,7 @@
         "SettingsLibDeviceStateRotationLock",
         "SettingsLibDisplayUtils",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.base",
diff --git a/packages/SettingsProvider/OWNERS b/packages/SettingsProvider/OWNERS
index 5ade971..86ae581 100644
--- a/packages/SettingsProvider/OWNERS
+++ b/packages/SettingsProvider/OWNERS
@@ -1,5 +1 @@
-hackbod@android.com
-hackbod@google.com
-narayan@google.com
-svetoslavganov@google.com
 include /PACKAGE_MANAGER_OWNERS
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 1d25ac7..e5dbe5f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -69,6 +69,7 @@
         Settings.Global.PRIVATE_DNS_SPECIFIER,
         Settings.Global.SOFT_AP_TIMEOUT_ENABLED,
         Settings.Global.ZEN_DURATION,
+        Settings.Global.REVERSE_CHARGING_AUTO_ON,
         Settings.Global.CHARGING_VIBRATION_ENABLED,
         Settings.Global.AWARE_ALLOWED,
         Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP,                   // moved to secure
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 91d2d1b..c6e9c03 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -143,6 +143,7 @@
         Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
         Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED,
         Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+        Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT,
         Settings.Secure.VOLUME_HUSH_GESTURE,
         Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT,
         Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
@@ -218,6 +219,7 @@
         Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED,
+        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE,
         Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,
         Settings.Secure.NOTIFICATION_BUBBLES,
         Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
@@ -244,6 +246,9 @@
         Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
         Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
         Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED,
-        Settings.Secure.HUB_MODE_TUTORIAL_STATE
+        Settings.Secure.HUB_MODE_TUTORIAL_STATE,
+        Settings.Secure.STYLUS_BUTTONS_ENABLED,
+        Settings.Secure.STYLUS_HANDWRITING_ENABLED,
+        Settings.Secure.DEFAULT_NOTE_TASK_PROFILE
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 248c60c..fe39c4f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -101,5 +101,10 @@
         Settings.System.CAMERA_FLASH_NOTIFICATION,
         Settings.System.SCREEN_FLASH_NOTIFICATION,
         Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
+        Settings.System.PEAK_REFRESH_RATE,
+        Settings.System.MIN_REFRESH_RATE,
+        Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
+        Settings.System.NOTIFICATION_COOLDOWN_ALL,
+        Settings.System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED,
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index ba06185..7e8fe7e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -171,6 +171,7 @@
         VALIDATORS.put(Global.WIFI_SCAN_THROTTLE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.APP_AUTO_RESTRICTION_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.ZEN_DURATION, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.REVERSE_CHARGING_AUTO_ON, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.REQUIRE_PASSWORD_TO_DECRYPT, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index bec1447..0727677 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -212,6 +212,7 @@
         VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.VOLUME_HUSH_GESTURE, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(
                 Secure.ENABLED_NOTIFICATION_LISTENERS,
@@ -308,6 +309,10 @@
         VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE,
+                new InclusiveIntegerRangeValidator(
+                        Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE,
+                        Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE_ALL));
         VALIDATORS.put(
                 Secure.ACCESSIBILITY_BUTTON_TARGETS,
                 ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
@@ -390,5 +395,9 @@
                 BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DND_CONFIGS_MIGRATED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.HUB_MODE_TUTORIAL_STATE, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.STYLUS_BUTTONS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.STYLUS_HANDWRITING_ENABLED,
+                new DiscreteValueValidator(new String[] {"-1", "0", "1"}));
+        VALIDATORS.put(Secure.DEFAULT_NOTE_TASK_PROFILE, NON_NEGATIVE_INTEGER_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 17ce7c7..eba74ab 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -21,6 +21,7 @@
 import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_FLOAT_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.VIBRATION_INTENSITY_VALIDATOR;
@@ -30,6 +31,7 @@
 import android.content.ComponentName;
 import android.hardware.display.ColorDisplayManager;
 import android.os.BatteryManager;
+import android.provider.Settings.Global;
 import android.provider.Settings.System;
 import android.util.ArrayMap;
 
@@ -120,6 +122,11 @@
         VALIDATORS.put(System.DISPLAY_COLOR_MODE_VENDOR_HINT, ANY_STRING_VALIDATOR);
         VALIDATORS.put(System.SCREEN_OFF_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(System.SCREEN_BRIGHTNESS_MODE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                System.SCREEN_BRIGHTNESS_FOR_ALS,
+                new InclusiveIntegerRangeValidator(
+                        System.SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT,
+                        System.SCREEN_BRIGHTNESS_AUTOMATIC_DIM));
         VALIDATORS.put(System.ADAPTIVE_SLEEP, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.MODE_RINGER_STREAMS_AFFECTED, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(System.MUTE_STREAMS_AFFECTED, NON_NEGATIVE_INTEGER_VALIDATOR);
@@ -231,5 +238,10 @@
         VALIDATORS.put(System.CAMERA_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION_COLOR, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(System.PEAK_REFRESH_RATE, NON_NEGATIVE_FLOAT_VALIDATOR);
+        VALIDATORS.put(System.MIN_REFRESH_RATE, NON_NEGATIVE_FLOAT_VALIDATOR);
+        VALIDATORS.put(System.NOTIFICATION_COOLDOWN_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.NOTIFICATION_COOLDOWN_ALL, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 3c8d4bc..f06b31c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1850,6 +1850,10 @@
                 SecureSettingsProto.Accessibility
                         .ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED);
         dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE,
+                SecureSettingsProto.Accessibility
+                        .ACCESSIBILITY_MAGNIFICATION_GESTURE);
+        dumpSetting(s, p,
                 Settings.Secure.HEARING_AID_RINGTONE_ROUTING,
                 SecureSettingsProto.Accessibility.HEARING_AID_RINGTONE_ROUTING);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 40f7ba6..46cd725 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -121,6 +121,7 @@
 import com.android.internal.accessibility.util.AccessibilityUtils;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.display.RefreshRateSettingsUtils;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.providers.settings.SettingsState.Setting;
@@ -2054,12 +2055,14 @@
             final Uri ringtoneUri = Uri.parse(value);
             // Stream selected ringtone into cache, so it's available for playback
             // when CE storage is still locked
-            try (InputStream in = openRingtone(getContext(), ringtoneUri);
-                 OutputStream out = new FileOutputStream(cacheFile)) {
-                FileUtils.copy(in, out);
-            } catch (IOException e) {
-                Slog.w(LOG_TAG, "Failed to cache ringtone: " + e);
-            }
+            Binder.withCleanCallingIdentity(() -> {
+                try (InputStream in = openRingtone(getContext(), ringtoneUri);
+                         OutputStream out = new FileOutputStream(cacheFile)) {
+                    FileUtils.copy(in, out);
+                } catch (IOException e) {
+                    Slog.w(LOG_TAG, "Failed to cache ringtone: " + e);
+                }
+            });
         }
         return true;
     }
@@ -3876,7 +3879,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 222;
+            private static final int SETTINGS_VERSION = 223;
 
             private final int mUserId;
 
@@ -5933,10 +5936,6 @@
 
                 if (currentVersion == 218) {
                     // Version 219: Removed
-                    // TODO(b/211737588): Back up the Smooth Display setting
-                    // Future upgrades to the `peak_refresh_rate` and `min_refresh_rate` settings
-                    // should account for the database in a non-upgraded and upgraded (change id:
-                    // Ib2cb2dd100f06f5452083b7606109a486e795a0e) state.
                     currentVersion = 219;
                 }
 
@@ -6002,6 +6001,56 @@
                     currentVersion = 222;
                 }
 
+                // Version 222: Set peak refresh rate and min refresh rate to infinity if it's
+                // meant to be the highest possible refresh rate. This is needed so that we can
+                // back up and restore those settings on other devices. Other devices might have
+                // different highest possible refresh rates.
+                if (currentVersion == 222) {
+                    final SettingsState systemSettings = getSystemSettingsLocked(userId);
+                    final Setting peakRefreshRateSetting =
+                            systemSettings.getSettingLocked(Settings.System.PEAK_REFRESH_RATE);
+                    final Setting minRefreshRateSetting =
+                            systemSettings.getSettingLocked(Settings.System.MIN_REFRESH_RATE);
+                    float highestRefreshRate = RefreshRateSettingsUtils
+                            .findHighestRefreshRateForDefaultDisplay(getContext());
+
+                    if (!peakRefreshRateSetting.isNull()) {
+                        try {
+                            float peakRefreshRate =
+                                    Float.parseFloat(peakRefreshRateSetting.getValue());
+                            if (Math.round(peakRefreshRate) == Math.round(highestRefreshRate)) {
+                                systemSettings.insertSettingLocked(
+                                        Settings.System.PEAK_REFRESH_RATE,
+                                        String.valueOf(Float.POSITIVE_INFINITY),
+                                        /* tag= */ null,
+                                        /* makeDefault= */ false,
+                                        SettingsState.SYSTEM_PACKAGE_NAME);
+                            }
+                        } catch (NumberFormatException e) {
+                            // Do nothing. Leave the value as is.
+                        }
+                    }
+
+                    if (!minRefreshRateSetting.isNull()) {
+                        try {
+                            float minRefreshRate =
+                                    Float.parseFloat(minRefreshRateSetting.getValue());
+                            if (Math.round(minRefreshRate) == Math.round(highestRefreshRate)) {
+                                systemSettings.insertSettingLocked(
+                                        Settings.System.MIN_REFRESH_RATE,
+                                        String.valueOf(Float.POSITIVE_INFINITY),
+                                        /* tag= */ null,
+                                        /* makeDefault= */ false,
+                                        SettingsState.SYSTEM_PACKAGE_NAME);
+                            }
+                        } catch (NumberFormatException e) {
+                            // Do nothing. Leave the value as is.
+                        }
+                    }
+
+                    currentVersion = 223;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index c0f6231..7bca944 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -98,9 +98,8 @@
                     Settings.System.VOLUME_VOICE, // deprecated since API 2?
                     Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug?
                     Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only
-                    Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
-                    Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.SCREEN_BRIGHTNESS_FLOAT,
+                    Settings.System.SCREEN_BRIGHTNESS_FOR_ALS,
                     Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE,
                     Settings.System.WEAR_TTS_PREWARM_ENABLED,
                     Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
@@ -734,7 +733,6 @@
                  Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
                  Settings.Secure.CONTENT_CAPTURE_ENABLED,
                  Settings.Secure.DEFAULT_INPUT_METHOD,
-                 Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
                  Settings.Secure.DEVICE_PAIRED,
                  Settings.Secure.DIALER_DEFAULT_APPLICATION,
                  Settings.Secure.DISABLED_PRINT_SERVICES,
@@ -804,8 +802,6 @@
                  Settings.Secure.SLEEP_TIMEOUT,
                  Settings.Secure.SMS_DEFAULT_APPLICATION,
                  Settings.Secure.SPELL_CHECKER_ENABLED,  // Intentionally removed in Q
-                 Settings.Secure.STYLUS_BUTTONS_ENABLED,
-                 Settings.Secure.STYLUS_HANDWRITING_ENABLED,
                  Settings.Secure.TRUST_AGENTS_INITIALIZED,
                  Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED,
                  Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index ee05f2d..e40fcb2 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -319,6 +319,8 @@
         "tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt",
         "tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt",
         "tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt",
+        "tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt",
+        "tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt",
 
         /* Bouncer UI tests */
         "tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt",
@@ -365,6 +367,42 @@
         "tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt",
         "tests/src/com/android/systemui/qs/tiles/base/**/*.kt",
         "tests/src/com/android/systemui/qs/tiles/viewmodel/**/*.kt",
+
+        /* Authentication */
+        "tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt",
+        "tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt",
+
+        /* Device entry */
+        "tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt",
+        "tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt",
+
+        /* Bouncer scene */
+        "tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt",
+        "tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt",
+        "tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt",
+        "tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt",
+        "tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt",
+        "tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt",
+        "tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt",
+
+        /* Lockscreen scene */
+        "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt",
+
+        /* Shade scene */
+        "tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt",
+        "tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt",
+
+        /* Quick Settings scene */
+        "tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt",
+
+        /* Flexiglass / Scene framework tests */
+        "tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt",
+        "tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt",
+        "tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt",
+        "tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt",
+        "tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt",
+        "tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt",
+        "tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt",
     ],
     path: "tests/src",
 }
@@ -428,7 +466,7 @@
         "hamcrest-library",
         "androidx.test.rules",
         "testables",
-        "truth-prebuilt",
+        "truth",
         "monet",
         "libmonet",
         "dagger2",
@@ -545,7 +583,7 @@
         "android.test.runner",
         "android.test.base",
         "android.test.mock",
-        "truth-prebuilt",
+        "truth",
     ],
 
     upstream: true,
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml
index f6dcdd3..b314c8e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml
@@ -8,7 +8,7 @@
     <string name="a11y_settings_label" msgid="3977714687248445050">"Erabilerraztasun-&amp;#173;ezarpenak"</string>
     <string name="power_label" msgid="7699720321491287839">"Bateria"</string>
     <string name="power_utterance" msgid="7444296686402104807">"Bateria kontrolatzeko aukerak"</string>
-    <string name="recent_apps_label" msgid="6583276995616385847">"Azken aplikazioak"</string>
+    <string name="recent_apps_label" msgid="6583276995616385847">"Azkenaldiko aplikazioak"</string>
     <string name="lockscreen_label" msgid="648347953557887087">"Pantaila blokeatua"</string>
     <string name="quick_settings_label" msgid="2999117381487601865">"Ezarpen bizkorrak"</string>
     <string name="notifications_label" msgid="6829741046963013567">"Jakinarazpenak"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 008732e..96e1e3f 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -63,6 +63,7 @@
 
     private static final String TAG = "A11yMenuService";
     private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L;
+    private static final long TAKE_SCREENSHOT_DELAY_MS = 100L;
 
     private static final int BRIGHTNESS_UP_INCREMENT_GAMMA =
             (int) Math.ceil(BrightnessUtils.GAMMA_SPACE_MAX * 0.11f);
@@ -301,7 +302,14 @@
         } else if (viewTag == ShortcutId.ID_NOTIFICATION_VALUE.ordinal()) {
             performGlobalActionInternal(GLOBAL_ACTION_NOTIFICATIONS);
         } else if (viewTag == ShortcutId.ID_SCREENSHOT_VALUE.ordinal()) {
-            performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT);
+            if (Flags.a11yMenuHideBeforeTakingAction()) {
+                // Delay before taking a screenshot to give time for the UI to close.
+                mHandler.postDelayed(
+                        () -> performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT),
+                        TAKE_SCREENSHOT_DELAY_MS);
+            } else {
+                performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT);
+            }
         }
 
         if (!Flags.a11yMenuHideBeforeTakingAction()) {
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp
index 538ecb3..3fc351c 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp
+++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp
@@ -32,7 +32,7 @@
         "androidx.test.ext.junit",
         "compatibility-device-util-axt",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     srcs: [
         "src/**/*.java",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 437f8af..2509cfd 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -13,3 +13,19 @@
     description: "Enables all the sysui classic flags that are marked as being in teamfood"
     bug: "302578396"
 }
+
+flag {
+    name: "notifications_footer_view_refactor"
+    namespace: "systemui"
+    description: "Enables the refactored version of the footer view in the notification shade "
+        "(containing the \"Clear all\" button). Should not bring any behavior changes"
+    bug: "293167744"
+}
+
+flag {
+    name: "notification_lifetime_extension_refactor"
+    namespace: "systemui"
+    description: "Enables moving notification lifetime extension management from SystemUI to "
+        "Notification Manager Service"
+    bug: "299448097"
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 0f2e4ba..4aac279 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -39,6 +39,7 @@
 import android.view.WindowManager
 import android.view.animation.Interpolator
 import android.view.animation.PathInterpolator
+import androidx.annotation.AnyThread
 import androidx.annotation.BinderThread
 import androidx.annotation.UiThread
 import com.android.app.animation.Interpolators
@@ -149,6 +150,10 @@
             override fun onLaunchAnimationProgress(linearProgress: Float) {
                 listeners.forEach { it.onLaunchAnimationProgress(linearProgress) }
             }
+
+            override fun onLaunchAnimationCancelled() {
+                listeners.forEach { it.onLaunchAnimationCancelled() }
+            }
         }
 
     /**
@@ -191,6 +196,7 @@
                     "ActivityLaunchAnimator.callback must be set before using this animator"
                 )
         val runner = createRunner(controller)
+        val runnerDelegate = runner.delegate!!
         val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen
 
         // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the
@@ -241,12 +247,15 @@
         // If we expect an animation, post a timeout to cancel it in case the remote animation is
         // never started.
         if (willAnimate) {
-            runner.delegate.postTimeout()
+            runnerDelegate.postTimeout()
 
             // Hide the keyguard using the launch animation instead of the default unlock animation.
             if (hideKeyguardWithAnimation) {
                 callback.hideKeyguardWithAnimation(runner)
             }
+        } else {
+            // We need to make sure delegate references are dropped to avoid memory leaks.
+            runner.dispose()
         }
     }
 
@@ -344,6 +353,13 @@
          */
         fun onLaunchAnimationEnd() {}
 
+        /**
+         * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after
+         * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
+         * before the cancellation.
+         */
+        fun onLaunchAnimationCancelled() {}
+
         /** Called when an activity launch animation made progress. */
         fun onLaunchAnimationProgress(linearProgress: Float) {}
     }
@@ -426,6 +442,39 @@
         fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {}
     }
 
+    /**
+     * Invokes [onAnimationComplete] when animation is either cancelled or completed. Delegates all
+     * events to the passed [delegate].
+     */
+    @VisibleForTesting
+    inner class DelegatingAnimationCompletionListener(
+        private val delegate: Listener?,
+        private val onAnimationComplete: () -> Unit
+    ) : Listener {
+        var cancelled = false
+
+        override fun onLaunchAnimationStart() {
+            delegate?.onLaunchAnimationStart()
+        }
+
+        override fun onLaunchAnimationProgress(linearProgress: Float) {
+            delegate?.onLaunchAnimationProgress(linearProgress)
+        }
+
+        override fun onLaunchAnimationEnd() {
+            delegate?.onLaunchAnimationEnd()
+            if (!cancelled) {
+                onAnimationComplete.invoke()
+            }
+        }
+
+        override fun onLaunchAnimationCancelled() {
+            cancelled = true
+            delegate?.onLaunchAnimationCancelled()
+            onAnimationComplete.invoke()
+        }
+    }
+
     @VisibleForTesting
     inner class Runner(
         controller: Controller,
@@ -436,11 +485,21 @@
         listener: Listener? = null
     ) : IRemoteAnimationRunner.Stub() {
         private val context = controller.launchContainer.context
-        internal val delegate: AnimationDelegate
+
+        // This is being passed across IPC boundaries and cycles (through PendingIntentRecords,
+        // etc.) are possible. So we need to make sure we drop any references that might
+        // transitively cause leaks when we're done with animation.
+        @VisibleForTesting var delegate: AnimationDelegate?
 
         init {
             delegate =
-                AnimationDelegate(controller, callback, listener, launchAnimator, disableWmTimeout)
+                AnimationDelegate(
+                    controller,
+                    callback,
+                    DelegatingAnimationCompletionListener(listener, this::dispose),
+                    launchAnimator,
+                    disableWmTimeout
+                )
         }
 
         @BinderThread
@@ -451,14 +510,33 @@
             nonApps: Array<out RemoteAnimationTarget>?,
             finishedCallback: IRemoteAnimationFinishedCallback?
         ) {
+            val delegate = delegate
             context.mainExecutor.execute {
-                delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+                if (delegate == null) {
+                    Log.i(TAG, "onAnimationStart called after completion")
+                    // Animation started too late and timed out already. We need to still
+                    // signal back that we're done with it.
+                    finishedCallback?.onAnimationFinished()
+                } else {
+                    delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+                }
             }
         }
 
         @BinderThread
         override fun onAnimationCancelled() {
-            context.mainExecutor.execute { delegate.onAnimationCancelled() }
+            val delegate = delegate
+            context.mainExecutor.execute {
+                delegate ?: Log.wtf(TAG, "onAnimationCancelled called after completion")
+                delegate?.onAnimationCancelled()
+            }
+        }
+
+        @AnyThread
+        fun dispose() {
+            // Drop references to animation controller once we're done with the animation
+            // to avoid leaking.
+            context.mainExecutor.execute { delegate = null }
         }
     }
 
@@ -584,6 +662,7 @@
                     )
                 }
                 controller.onLaunchAnimationCancelled()
+                listener?.onLaunchAnimationCancelled()
                 return
             }
 
@@ -821,6 +900,7 @@
                 Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]")
             }
             controller.onLaunchAnimationCancelled()
+            listener?.onLaunchAnimationCancelled()
         }
 
         @UiThread
@@ -842,6 +922,7 @@
                 )
             }
             controller.onLaunchAnimationCancelled()
+            listener?.onLaunchAnimationCancelled()
         }
 
         private fun IRemoteAnimationFinishedCallback.invoke() {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index bd3706e..00d9056 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -70,8 +70,10 @@
          * If a new layout change happens while an animation is already in progress, the animation
          * is updated to continue from the current values to the new end state.
          *
-         * A set of [excludedViews] can be passed. If any dependent view from [rootView] matches an
-         * entry in this set, changes to that view will not be animated.
+         * By default, child views whole layout changes are animated as well. However, this can be
+         * controlled by [animateChildren]. If children are included, a set of [excludedViews] can
+         * be passed. If any dependent view from [rootView] matches an entry in this set, changes to
+         * that view will not be animated.
          *
          * The animator continues to respond to layout changes until [stopAnimating] is called.
          *
@@ -86,6 +88,7 @@
             rootView: View,
             interpolator: Interpolator = DEFAULT_INTERPOLATOR,
             duration: Long = DEFAULT_DURATION,
+            animateChildren: Boolean = true,
             excludedViews: Set<View> = emptySet()
         ): Boolean {
             return animate(
@@ -93,6 +96,7 @@
                 interpolator,
                 duration,
                 ephemeral = false,
+                animateChildren = animateChildren,
                 excludedViews = excludedViews
             )
         }
@@ -106,6 +110,7 @@
             rootView: View,
             interpolator: Interpolator = DEFAULT_INTERPOLATOR,
             duration: Long = DEFAULT_DURATION,
+            animateChildren: Boolean = true,
             excludedViews: Set<View> = emptySet()
         ): Boolean {
             return animate(
@@ -113,6 +118,7 @@
                 interpolator,
                 duration,
                 ephemeral = true,
+                animateChildren = animateChildren,
                 excludedViews = excludedViews
             )
         }
@@ -122,6 +128,7 @@
             interpolator: Interpolator,
             duration: Long,
             ephemeral: Boolean,
+            animateChildren: Boolean,
             excludedViews: Set<View> = emptySet()
         ): Boolean {
             if (
@@ -137,7 +144,13 @@
             }
 
             val listener = createUpdateListener(interpolator, duration, ephemeral)
-            addListener(rootView, listener, recursive = true, excludedViews = excludedViews)
+            addListener(
+                rootView,
+                listener,
+                recursive = true,
+                animateChildren = animateChildren,
+                excludedViews = excludedViews
+            )
             return true
         }
 
@@ -940,6 +953,7 @@
             view: View,
             listener: View.OnLayoutChangeListener,
             recursive: Boolean = false,
+            animateChildren: Boolean = true,
             excludedViews: Set<View> = emptySet()
         ) {
             if (excludedViews.contains(view)) return
@@ -952,12 +966,13 @@
 
             view.addOnLayoutChangeListener(listener)
             view.setTag(R.id.tag_layout_listener, listener)
-            if (view is ViewGroup && recursive) {
+            if (animateChildren && view is ViewGroup && recursive) {
                 for (i in 0 until view.childCount) {
                     addListener(
                         view.getChildAt(i),
                         listener,
                         recursive = true,
+                        animateChildren = animateChildren,
                         excludedViews = excludedViews
                     )
                 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
index a62c984..ce96bbf 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
@@ -21,6 +21,7 @@
 import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.movableContentOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
@@ -48,28 +49,51 @@
 /** An element on screen, that can be composed in one or more scenes. */
 internal class Element(val key: ElementKey) {
     /**
-     * The last offset assigned to this element, relative to the SceneTransitionLayout containing
-     * it.
+     * The last values of this element, coming from any scene. Note that this value will be unstable
+     * if this element is present in multiple scenes but the shared element animation is disabled,
+     * given that multiple instances of the element with different states will write to these
+     * values. You should prefer using [TargetValues.lastValues] in the current scene if it is
+     * defined.
      */
-    var lastOffset = Offset.Unspecified
-
-    /** The last size assigned to this element. */
-    var lastSize = SizeUnspecified
-
-    /** The last alpha assigned to this element. */
-    var lastAlpha = 1f
+    val lastSharedValues = Values()
 
     /** The mapping between a scene and the values/state this element has in that scene, if any. */
-    val sceneValues = SnapshotStateMap<SceneKey, SceneValues>()
+    val sceneValues = SnapshotStateMap<SceneKey, TargetValues>()
+
+    /**
+     * The movable content of this element, if this element is composed using
+     * [SceneScope.MovableElement].
+     */
+    val movableContent by
+        // This is only accessed from the composition (main) thread, so no need to use the default
+        // lock of lazy {} to synchronize.
+        lazy(mode = LazyThreadSafetyMode.NONE) {
+            movableContentOf { content: @Composable () -> Unit -> content() }
+        }
 
     override fun toString(): String {
         return "Element(key=$key)"
     }
 
+    /** The current values of this element, either in a specific scene or in a shared context. */
+    class Values {
+        /** The offset of the element, relative to the SceneTransitionLayout containing it. */
+        var offset = Offset.Unspecified
+
+        /** The size of this element. */
+        var size = SizeUnspecified
+
+        /** The alpha of this element. */
+        var alpha = AlphaUnspecified
+    }
+
     /** The target values of this element in a given scene. */
-    class SceneValues {
-        var size by mutableStateOf(SizeUnspecified)
-        var offset by mutableStateOf(Offset.Unspecified)
+    class TargetValues {
+        val lastValues = Values()
+
+        var targetSize by mutableStateOf(SizeUnspecified)
+        var targetOffset by mutableStateOf(Offset.Unspecified)
+
         val sharedValues = SnapshotStateMap<ValueKey, SharedValue<*>>()
     }
 
@@ -80,6 +104,7 @@
 
     companion object {
         val SizeUnspecified = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
+        val AlphaUnspecified = Float.MIN_VALUE
     }
 }
 
@@ -91,7 +116,7 @@
     scene: Scene,
     key: ElementKey,
 ): Modifier {
-    val sceneValues = remember(scene, key) { Element.SceneValues() }
+    val sceneValues = remember(scene, key) { Element.TargetValues() }
     val element =
         // Get the element associated to [key] if it was already composed in another scene,
         // otherwise create it and add it to our Map<ElementKey, Element>. This is done inside a
@@ -108,6 +133,8 @@
 
             element
         }
+    val lastSharedValues = element.lastSharedValues
+    val lastSceneValues = sceneValues.lastValues
 
     DisposableEffect(scene, sceneValues, element) {
         onDispose {
@@ -121,13 +148,14 @@
     }
 
     val alpha =
-        remember(layoutImpl, element, scene) {
-            derivedStateOf { elementAlpha(layoutImpl, element, scene) }
+        remember(layoutImpl, element, scene, sceneValues) {
+            derivedStateOf { elementAlpha(layoutImpl, element, scene, sceneValues) }
         }
     val isOpaque by remember(alpha) { derivedStateOf { alpha.value == 1f } }
     SideEffect {
-        if (isOpaque && element.lastAlpha != 1f) {
-            element.lastAlpha = 1f
+        if (isOpaque) {
+            lastSharedValues.alpha = 1f
+            lastSceneValues.alpha = 1f
         }
     }
 
@@ -148,7 +176,8 @@
             Modifier.graphicsLayer {
                 val alpha = alpha.value
                 this.alpha = alpha
-                element.lastAlpha = alpha
+                lastSharedValues.alpha = alpha
+                lastSceneValues.alpha = alpha
             }
         }
         .testTag(key.testTag)
@@ -220,7 +249,7 @@
     layoutImpl: SceneTransitionLayoutImpl,
     scene: Scene,
     element: Element,
-    sceneValues: Element.SceneValues,
+    sceneValues: Element.TargetValues,
 ): Modifier {
     when (val state = layoutImpl.state.transitionState) {
         is TransitionState.Idle -> return this
@@ -248,7 +277,8 @@
 private fun elementAlpha(
     layoutImpl: SceneTransitionLayoutImpl,
     element: Element,
-    scene: Scene
+    scene: Scene,
+    sceneValues: Element.TargetValues,
 ): Float {
     return computeValue(
             layoutImpl,
@@ -258,7 +288,11 @@
             transformation = { it.alpha },
             idleValue = 1f,
             currentValue = { 1f },
-            lastValue = { element.lastAlpha },
+            lastValue = {
+                sceneValues.lastValues.alpha.takeIf { it != Element.AlphaUnspecified }
+                    ?: element.lastSharedValues.alpha.takeIf { it != Element.AlphaUnspecified }
+                        ?: 1f
+            },
             ::lerp,
         )
         .coerceIn(0f, 1f)
@@ -269,15 +303,15 @@
     layoutImpl: SceneTransitionLayoutImpl,
     scene: Scene,
     element: Element,
-    sceneValues: Element.SceneValues,
+    sceneValues: Element.TargetValues,
     measurable: Measurable,
     constraints: Constraints,
 ): Placeable {
     // Update the size this element has in this scene when idle.
     val targetSizeInScene = lookaheadSize
-    if (targetSizeInScene != sceneValues.size) {
+    if (targetSizeInScene != sceneValues.targetSize) {
         // TODO(b/290930950): Better handle when this changes to avoid instant size jumps.
-        sceneValues.size = targetSizeInScene
+        sceneValues.targetSize = targetSizeInScene
     }
 
     // Some lambdas called (max once) by computeValue() will need to measure [measurable], in which
@@ -292,17 +326,14 @@
             layoutImpl,
             scene,
             element,
-            sceneValue = { it.size },
+            sceneValue = { it.targetSize },
             transformation = { it.size },
             idleValue = lookaheadSize,
             currentValue = { measurable.measure(constraints).also { maybePlaceable = it }.size() },
             lastValue = {
-                val lastSize = element.lastSize
-                if (lastSize != Element.SizeUnspecified) {
-                    lastSize
-                } else {
-                    measurable.measure(constraints).also { maybePlaceable = it }.size()
-                }
+                sceneValues.lastValues.size.takeIf { it != Element.SizeUnspecified }
+                    ?: element.lastSharedValues.size.takeIf { it != Element.SizeUnspecified }
+                        ?: measurable.measure(constraints).also { maybePlaceable = it }.size()
             },
             ::lerp,
         )
@@ -316,7 +347,9 @@
                 )
             )
 
-    element.lastSize = placeable.size()
+    val size = placeable.size()
+    element.lastSharedValues.size = size
+    sceneValues.lastValues.size = size
     return placeable
 }
 
@@ -325,7 +358,7 @@
     layoutImpl: SceneTransitionLayoutImpl,
     scene: Scene,
     element: Element,
-    sceneValues: Element.SceneValues,
+    sceneValues: Element.TargetValues,
     placeable: Placeable,
     placementScope: Placeable.PlacementScope,
 ) {
@@ -334,9 +367,9 @@
         // when idle.
         val coords = coordinates!!
         val targetOffsetInScene = lookaheadScopeCoordinates.localLookaheadPositionOf(coords)
-        if (targetOffsetInScene != sceneValues.offset) {
+        if (targetOffsetInScene != sceneValues.targetOffset) {
             // TODO(b/290930950): Better handle when this changes to avoid instant offset jumps.
-            sceneValues.offset = targetOffsetInScene
+            sceneValues.targetOffset = targetOffsetInScene
         }
 
         val currentOffset = lookaheadScopeCoordinates.localPositionOf(coords, Offset.Zero)
@@ -345,22 +378,20 @@
                 layoutImpl,
                 scene,
                 element,
-                sceneValue = { it.offset },
+                sceneValue = { it.targetOffset },
                 transformation = { it.offset },
                 idleValue = targetOffsetInScene,
                 currentValue = { currentOffset },
                 lastValue = {
-                    val lastValue = element.lastOffset
-                    if (lastValue.isSpecified) {
-                        lastValue
-                    } else {
-                        currentOffset
-                    }
+                    sceneValues.lastValues.offset.takeIf { it.isSpecified }
+                        ?: element.lastSharedValues.offset.takeIf { it.isSpecified }
+                            ?: currentOffset
                 },
                 ::lerp,
             )
 
-        element.lastOffset = targetOffset
+        element.lastSharedValues.offset = targetOffset
+        sceneValues.lastValues.offset = targetOffset
         placeable.place((targetOffset - currentOffset).round())
     }
 }
@@ -391,7 +422,7 @@
     layoutImpl: SceneTransitionLayoutImpl,
     scene: Scene,
     element: Element,
-    sceneValue: (Element.SceneValues) -> T,
+    sceneValue: (Element.TargetValues) -> T,
     transformation: (ElementTransformations) -> PropertyTransformation<T>?,
     idleValue: T,
     currentValue: () -> T,
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
index b7acc48..bc015ee 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
@@ -22,7 +22,7 @@
  * A base class to create unique keys, associated to an [identity] that is used to check the
  * equality of two key instances.
  */
-sealed class Key(val name: String, val identity: Any) {
+sealed class Key(val debugName: String, val identity: Any) {
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (this.javaClass != other?.javaClass) return false
@@ -34,7 +34,7 @@
     }
 
     override fun toString(): String {
-        return "Key(name=$name)"
+        return "Key(debugName=$debugName)"
     }
 }
 
@@ -49,7 +49,7 @@
     val rootElementKey = ElementKey(name, identity)
 
     override fun toString(): String {
-        return "SceneKey(name=$name)"
+        return "SceneKey(debugName=$debugName)"
     }
 }
 
@@ -71,7 +71,7 @@
     }
 
     override fun toString(): String {
-        return "ElementKey(name=$name)"
+        return "ElementKey(debugName=$debugName)"
     }
 
     companion object {
@@ -89,6 +89,6 @@
 /** Key for a shared value of an element. */
 class ValueKey(name: String, identity: Any = Object()) : Key(name, identity) {
     override fun toString(): String {
-        return "ValueKey(name=$name)"
+        return "ValueKey(debugName=$debugName)"
     }
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/MovableElement.kt
new file mode 100644
index 0000000..11bbf2a
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/MovableElement.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2023 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.compose.animation.scene
+
+import android.graphics.Picture
+import android.util.Log
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.graphics.drawscope.draw
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.nativeCanvas
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.IntSize
+
+private const val TAG = "MovableElement"
+
+private object MovableElementScopeImpl : MovableElementScope
+
+@Composable
+internal fun MovableElement(
+    layoutImpl: SceneTransitionLayoutImpl,
+    scene: Scene,
+    key: ElementKey,
+    modifier: Modifier,
+    content: @Composable MovableElementScope.() -> Unit,
+) {
+    Box(modifier.element(layoutImpl, scene, key)) {
+        // Get the Element from the map. It will always be the same and we don't want to recompose
+        // every time an element is added/removed from SceneTransitionLayoutImpl.elements, so we
+        // disable read observation during the look-up in that map.
+        val element = Snapshot.withoutReadObservation { layoutImpl.elements.getValue(key) }
+
+        // The [Picture] to which we save the last drawing commands of this element. This is
+        // necessary because the content of this element might not be composed in this scene, in
+        // which case we still need to draw it.
+        val picture = remember { Picture() }
+
+        if (shouldComposeMovableElement(layoutImpl, scene.key, element)) {
+            Box(
+                Modifier.drawWithCache {
+                    val width = size.width.toInt()
+                    val height = size.height.toInt()
+
+                    onDrawWithContent {
+                        // Save the draw commands into [picture] for later to draw the last content
+                        // even when this movable content is not composed.
+                        val pictureCanvas = Canvas(picture.beginRecording(width, height))
+                        draw(this, this.layoutDirection, pictureCanvas, this.size) {
+                            this@onDrawWithContent.drawContent()
+                        }
+                        picture.endRecording()
+
+                        // Draw the content.
+                        drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
+                    }
+                }
+            ) {
+                element.movableContent { MovableElementScopeImpl.content() }
+            }
+        } else {
+            // If we are not composed, we draw the previous drawing commands at the same size as the
+            // movable content when it was composed in this scene.
+            val sceneValues = element.sceneValues.getValue(scene.key)
+
+            Spacer(
+                Modifier.layout { measurable, _ ->
+                        val size =
+                            sceneValues.targetSize.takeIf { it != Element.SizeUnspecified }
+                                ?: IntSize.Zero
+                        val placeable =
+                            measurable.measure(Constraints.fixed(size.width, size.height))
+                        layout(size.width, size.height) { placeable.place(0, 0) }
+                    }
+                    .drawBehind {
+                        drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
+                    }
+            )
+        }
+    }
+}
+
+private fun shouldComposeMovableElement(
+    layoutImpl: SceneTransitionLayoutImpl,
+    scene: SceneKey,
+    element: Element,
+): Boolean {
+    val transitionState = layoutImpl.state.transitionState
+
+    // If we are idle, there is only one [scene] that is composed so we can compose our movable
+    // content here.
+    if (transitionState is TransitionState.Idle) {
+        check(transitionState.currentScene == scene)
+        return true
+    }
+
+    val fromScene = (transitionState as TransitionState.Transition).fromScene
+    val toScene = transitionState.toScene
+    if (fromScene == toScene) {
+        check(fromScene == scene)
+        return true
+    }
+
+    val fromReady = layoutImpl.isSceneReady(fromScene)
+    val toReady = layoutImpl.isSceneReady(toScene)
+
+    val otherScene =
+        when (scene) {
+            fromScene -> toScene
+            toScene -> fromScene
+            else ->
+                error(
+                    "shouldComposeMovableElement(scene=$scene) called with fromScene=$fromScene " +
+                        "and toScene=$toScene"
+                )
+        }
+
+    val isShared = otherScene in element.sceneValues
+
+    if (isShared && !toReady && !fromReady) {
+        // This should usually not happen given that fromScene should be ready, but let's log a
+        // warning here in case it does so it helps debugging flicker issues caused by this part of
+        // the code.
+        Log.w(
+            TAG,
+            "MovableElement $element might have to be composed for the first time in both " +
+                "fromScene=$fromScene and toScene=$toScene. This will probably lead to a flicker " +
+                "where the size of the element will jump from IntSize.Zero to its actual size " +
+                "during the transition."
+        )
+    }
+
+    // Element is not shared in this transition.
+    if (!isShared) {
+        return true
+    }
+
+    // toScene is not ready (because we are composing it for the first time), so we compose it there
+    // first. This is the most common scenario when starting a transition that has a shared movable
+    // element.
+    if (!toReady) {
+        return scene == toScene
+    }
+
+    // This should usually not happen, but if we are also composing for the first time in fromScene
+    // then we should compose it there only.
+    if (!fromReady) {
+        return scene == fromScene
+    }
+
+    // If we are ready in both scenes, then compose in the scene that has the highest zIndex (unless
+    // it is a background) given that this is the one that is going to be drawn.
+    val isHighestScene = layoutImpl.scene(scene).zIndex > layoutImpl.scene(otherScene).zIndex
+    return if (element.key.isBackground) {
+        !isHighestScene
+    } else {
+        isHighestScene
+    }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
index 3985233..3fd6828 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
@@ -90,4 +90,13 @@
             canOverflow,
         )
     }
+
+    @Composable
+    override fun MovableElement(
+        key: ElementKey,
+        modifier: Modifier,
+        content: @Composable MovableElementScope.() -> Unit,
+    ) {
+        MovableElement(layoutImpl, scene, key, modifier, content)
+    }
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 39173d9..4283c0e 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -85,6 +85,13 @@
     )
 }
 
+/**
+ * A DSL marker to prevent people from nesting calls to Modifier.element() inside a MovableElement,
+ * which is not supported.
+ */
+@DslMarker annotation class ElementDsl
+
+@ElementDsl
 interface SceneScope {
     /**
      * Tag an element identified by [key].
@@ -95,12 +102,37 @@
      * Additionally, this [key] will be used to detect elements that are shared between scenes to
      * automatically interpolate their size, offset and [shared values][animateSharedValueAsState].
      *
+     * Note that shared elements tagged using this function will be duplicated in each scene they
+     * are part of, so any **internal** state (e.g. state created using `remember {
+     * mutableStateOf(...) }`) will be lost. If you need to preserve internal state, you should use
+     * [MovableElement] instead.
+     *
+     * @see MovableElement
+     *
      * TODO(b/291566282): Migrate this to the new Modifier Node API and remove the @Composable
      *   constraint.
      */
     @Composable fun Modifier.element(key: ElementKey): Modifier
 
     /**
+     * Create a *movable* element identified by [key].
+     *
+     * This creates an element that will be automatically shared when present in multiple scenes and
+     * that can be transformed during transitions, the same way that [element] does. The major
+     * difference with [element] is that elements created with [MovableElement] will be "moved" and
+     * composed only once during transitions (as opposed to [element] that duplicates shared
+     * elements) so that any internal state is preserved during and after the transition.
+     *
+     * @see element
+     */
+    @Composable
+    fun MovableElement(
+        key: ElementKey,
+        modifier: Modifier,
+        content: @Composable MovableElementScope.() -> Unit,
+    )
+
+    /**
      * Animate some value of a shared element.
      *
      * @param value the value of this shared value in the current scene.
@@ -126,14 +158,31 @@
     ): State<T>
 }
 
+// TODO(b/291053742): Add animateSharedValueAsState(targetValue) without any ValueKey and ElementKey
+// arguments to allow sharing values inside a movable element.
+@ElementDsl interface MovableElementScope
+
 /** An action performed by the user. */
 sealed interface UserAction
 
 /** The user navigated back, either using a gesture or by triggering a KEYCODE_BACK event. */
-object Back : UserAction
+data object Back : UserAction
 
 /** The user swiped on the container. */
-enum class Swipe : UserAction {
+data class Swipe(
+    val direction: SwipeDirection,
+    val pointerCount: Int = 1,
+    val fromEdge: Edge? = null,
+) : UserAction {
+    companion object {
+        val Left = Swipe(SwipeDirection.Left)
+        val Up = Swipe(SwipeDirection.Up)
+        val Right = Swipe(SwipeDirection.Right)
+        val Down = Swipe(SwipeDirection.Down)
+    }
+}
+
+enum class SwipeDirection {
     Up,
     Down,
     Left,
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index b3a7a8e9..4952270 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -199,4 +199,6 @@
         return readyScenes.containsKey(transition.fromScene) &&
             readyScenes.containsKey(transition.toScene)
     }
+
+    internal fun isSceneReady(scene: SceneKey): Boolean = readyScenes.containsKey(scene)
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
index d4ed697..95385d5 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
@@ -34,12 +34,12 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
         transition: TransitionState.Transition,
         value: IntSize,
     ): IntSize {
         fun anchorSizeIn(scene: SceneKey): IntSize {
-            val size = layoutImpl.elements[anchor]?.sceneValues?.get(scene)?.size
+            val size = layoutImpl.elements[anchor]?.sceneValues?.get(scene)?.targetSize
             return if (size != null && size != Element.SizeUnspecified) {
                 size
             } else {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
index 8a5bd74..a1d6319 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
@@ -35,13 +35,13 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
         transition: TransitionState.Transition,
         value: Offset,
     ): Offset {
         val anchor = layoutImpl.elements[anchor] ?: return value
         fun anchorOffsetIn(scene: SceneKey): Offset? {
-            return anchor.sceneValues[scene]?.offset?.takeIf { it.isSpecified }
+            return anchor.sceneValues[scene]?.targetOffset?.takeIf { it.isSpecified }
         }
 
         // [element] will move the same amount as [anchor] does.
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
index 5cdce94..840800d 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
@@ -34,12 +34,12 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
         transition: TransitionState.Transition,
         value: Offset
     ): Offset {
         val sceneSize = scene.size
-        val elementSize = sceneValues.size
+        val elementSize = sceneValues.targetSize
         if (elementSize == Element.SizeUnspecified) {
             return value
         }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Fade.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Fade.kt
index 0a5ac54..17032dc 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Fade.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Fade.kt
@@ -30,7 +30,7 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
         transition: TransitionState.Transition,
         value: Float
     ): Float {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/PunchHole.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/PunchHole.kt
index 73b366e..62d67f0 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/PunchHole.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/PunchHole.kt
@@ -47,14 +47,14 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
     ): Modifier {
         return drawWithContent {
             val bounds = layoutImpl.elements[bounds]
             if (
                 bounds == null ||
-                    bounds.lastSize == Element.SizeUnspecified ||
-                    bounds.lastOffset == Offset.Unspecified
+                    bounds.lastSharedValues.size == Element.SizeUnspecified ||
+                    bounds.lastSharedValues.offset == Offset.Unspecified
             ) {
                 drawContent()
                 return@drawWithContent
@@ -64,7 +64,7 @@
                 canvas.withSaveLayer(size.toRect(), Paint()) {
                     drawContent()
 
-                    val offset = bounds.lastOffset - element.lastOffset
+                    val offset = bounds.lastSharedValues.offset - element.lastSharedValues.offset
                     translate(offset.x, offset.y) { drawHole(bounds) }
                 }
             }
@@ -72,7 +72,7 @@
     }
 
     private fun DrawScope.drawHole(bounds: Element) {
-        val boundsSize = bounds.lastSize.toSize()
+        val boundsSize = bounds.lastSharedValues.size.toSize()
         if (shape == RectangleShape) {
             drawRect(Color.Black, size = boundsSize, blendMode = BlendMode.DstOut)
             return
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/ScaleSize.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
index ce754dc..233ae59 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
@@ -37,7 +37,7 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
         transition: TransitionState.Transition,
         value: IntSize,
     ): IntSize {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt
index a650254..2ef8d56 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -59,7 +59,7 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
     ): Modifier
 }
 
@@ -74,7 +74,7 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
         transition: TransitionState.Transition,
         value: T,
     ): T
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Translate.kt
index 8abca61..864b937 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Translate.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Translate.kt
@@ -35,7 +35,7 @@
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
         element: Element,
-        sceneValues: Element.SceneValues,
+        sceneValues: Element.TargetValues,
         transition: TransitionState.Transition,
         value: Offset,
     ): Offset {
diff --git a/packages/SystemUI/compose/core/tests/Android.bp b/packages/SystemUI/compose/core/tests/Android.bp
index 52c6385..8e9c586 100644
--- a/packages/SystemUI/compose/core/tests/Android.bp
+++ b/packages/SystemUI/compose/core/tests/Android.bp
@@ -43,7 +43,7 @@
         "androidx.compose.ui_ui-test-junit4",
         "androidx.compose.ui_ui-test-manifest",
 
-        "truth-prebuilt",
+        "truth",
     ],
 
     kotlincflags: ["-Xjvm-default=all"],
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
new file mode 100644
index 0000000..4204cd5
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2023 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.compose.animation.scene
+
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasText
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onAllNodesWithText
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.test.assertSizeIsEqualTo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class MovableElementTest {
+    @get:Rule val rule = createComposeRule()
+
+    /** An element that displays a counter that is incremented whenever this element is clicked. */
+    @Composable
+    private fun Counter(modifier: Modifier = Modifier) {
+        var count by remember { mutableIntStateOf(0) }
+        Box(modifier.fillMaxSize().clickable { count++ }) { Text("count: $count") }
+    }
+
+    @Composable
+    private fun SceneScope.MovableCounter(key: ElementKey, modifier: Modifier) {
+        MovableElement(key, modifier) { Counter() }
+    }
+
+    @Test
+    fun modifierElementIsDuplicatedDuringTransitions() {
+        rule.testTransition(
+            fromSceneContent = {
+                Box(Modifier.element(TestElements.Foo).size(50.dp)) { Counter() }
+            },
+            toSceneContent = { Box(Modifier.element(TestElements.Foo).size(100.dp)) { Counter() } },
+            transition = { spec = tween(durationMillis = 16 * 4, easing = LinearEasing) },
+            fromScene = TestScenes.SceneA,
+            toScene = TestScenes.SceneB,
+        ) {
+            before {
+                // Click 3 times on the counter.
+                rule.onNodeWithText("count: 0").assertIsDisplayed().performClick()
+                rule.onNodeWithText("count: 1").assertIsDisplayed().performClick()
+                rule.onNodeWithText("count: 2").assertIsDisplayed().performClick()
+                rule
+                    .onNodeWithText("count: 3")
+                    .assertIsDisplayed()
+                    .assertSizeIsEqualTo(50.dp, 50.dp)
+
+                // There are no other counters.
+                assertThat(
+                        rule
+                            .onAllNodesWithText("count: ", substring = true)
+                            .fetchSemanticsNodes()
+                            .size
+                    )
+                    .isEqualTo(1)
+            }
+
+            at(32) {
+                // In the middle of the transition, there are 2 copies of the counter: the previous
+                // one from scene A (equal to 3) and the new one from scene B (equal to 0).
+                rule
+                    .onNode(
+                        hasText("count: 3") and
+                            hasParent(isElement(TestElements.Foo, scene = TestScenes.SceneA))
+                    )
+                    .assertIsDisplayed()
+                    .assertSizeIsEqualTo(75.dp, 75.dp)
+
+                rule
+                    .onNode(
+                        hasText("count: 0") and
+                            hasParent(isElement(TestElements.Foo, scene = TestScenes.SceneB))
+                    )
+                    .assertIsDisplayed()
+                    .assertSizeIsEqualTo(75.dp, 75.dp)
+
+                // There are exactly 2 counters.
+                assertThat(
+                        rule
+                            .onAllNodesWithText("count: ", substring = true)
+                            .fetchSemanticsNodes()
+                            .size
+                    )
+                    .isEqualTo(2)
+            }
+
+            after {
+                // At the end of the transition, only the counter from scene B is composed.
+                rule
+                    .onNodeWithText("count: 0")
+                    .assertIsDisplayed()
+                    .assertSizeIsEqualTo(100.dp, 100.dp)
+
+                // There are no other counters.
+                assertThat(
+                        rule
+                            .onAllNodesWithText("count: ", substring = true)
+                            .fetchSemanticsNodes()
+                            .size
+                    )
+                    .isEqualTo(1)
+            }
+        }
+    }
+
+    @Test
+    fun movableElementIsMovedAndComposedOnlyOnce() {
+        rule.testTransition(
+            fromSceneContent = { MovableCounter(TestElements.Foo, Modifier.size(50.dp)) },
+            toSceneContent = { MovableCounter(TestElements.Foo, Modifier.size(100.dp)) },
+            transition = { spec = tween(durationMillis = 16 * 4, easing = LinearEasing) },
+            fromScene = TestScenes.SceneA,
+            toScene = TestScenes.SceneB,
+        ) {
+            before {
+                // Click 3 times on the counter.
+                rule.onNodeWithText("count: 0").assertIsDisplayed().performClick()
+                rule.onNodeWithText("count: 1").assertIsDisplayed().performClick()
+                rule.onNodeWithText("count: 2").assertIsDisplayed().performClick()
+                rule
+                    .onNodeWithText("count: 3")
+                    .assertIsDisplayed()
+                    .assertSizeIsEqualTo(50.dp, 50.dp)
+
+                // There are no other counters.
+                assertThat(
+                        rule
+                            .onAllNodesWithText("count: ", substring = true)
+                            .fetchSemanticsNodes()
+                            .size
+                    )
+                    .isEqualTo(1)
+            }
+
+            at(32) {
+                // During the transition, there is a single counter that is moved, with the current
+                // value.
+                rule
+                    .onNode(hasText("count: 3"))
+                    .assertIsDisplayed()
+                    .assertSizeIsEqualTo(75.dp, 75.dp)
+
+                // There are no other counters.
+                assertThat(
+                        rule
+                            .onAllNodesWithText("count: ", substring = true)
+                            .fetchSemanticsNodes()
+                            .size
+                    )
+                    .isEqualTo(1)
+            }
+
+            after {
+                // At the end of the transition, the counter still has the current value.
+                rule
+                    .onNodeWithText("count: 3")
+                    .assertIsDisplayed()
+                    .assertSizeIsEqualTo(100.dp, 100.dp)
+
+                // There are no other counters.
+                assertThat(
+                        rule
+                            .onAllNodesWithText("count: ", substring = true)
+                            .fetchSemanticsNodes()
+                            .size
+                    )
+                    .isEqualTo(1)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 328866e..5afd420 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -117,7 +117,7 @@
                 .size(size)
                 .background(Color.Red)
                 .element(TestElements.Foo)
-                .testTag(TestElements.Foo.name)
+                .testTag(TestElements.Foo.debugName)
         ) {
             // Offset the single child of Foo by some animated shared offset.
             val offset by animateSharedDpAsState(childOffset, TestValues.Value1, TestElements.Foo)
@@ -129,7 +129,7 @@
                     }
                     .size(30.dp)
                     .background(Color.Blue)
-                    .testTag(TestElements.Bar.name)
+                    .testTag(TestElements.Bar.debugName)
             )
         }
     }
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 2232370..df3b72a 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -63,7 +63,7 @@
             { currentScene = it },
             EmptyTestTransitions,
             state = layoutState,
-            modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.name),
+            modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.debugName),
         ) {
             scene(
                 TestScenes.SceneA,
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
index 268057f..e0ae1be 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
@@ -22,13 +22,13 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.SemanticsMatcher
 import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.SemanticsNodeInteractionCollection
 import androidx.compose.ui.test.hasParent
 import androidx.compose.ui.test.hasTestTag
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.onAllNodesWithTag
-import androidx.compose.ui.test.onNodeWithTag
 
 @DslMarker annotation class TransitionTestDsl
 
@@ -63,6 +63,8 @@
 
 @TransitionTestDsl
 interface TransitionTestAssertionScope {
+    fun isElement(element: ElementKey, scene: SceneKey? = null): SemanticsMatcher
+
     /**
      * Assert on [element].
      *
@@ -130,15 +132,19 @@
     val test = transitionTest(builder)
     val assertionScope =
         object : TransitionTestAssertionScope {
+            override fun isElement(element: ElementKey, scene: SceneKey?): SemanticsMatcher {
+                return if (scene == null) {
+                    hasTestTag(element.testTag)
+                } else {
+                    hasTestTag(element.testTag) and hasParent(hasTestTag(scene.testTag))
+                }
+            }
+
             override fun onElement(
                 element: ElementKey,
                 scene: SceneKey?
             ): SemanticsNodeInteraction {
-                return if (scene == null) {
-                    onNodeWithTag(element.testTag)
-                } else {
-                    onNode(hasTestTag(element.testTag) and hasParent(hasTestTag(scene.testTag)))
-                }
+                return onNode(isElement(element, scene))
             }
 
             override fun onSharedElement(element: ElementKey): SemanticsNodeInteractionCollection {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index a9944f7..f2b7b32 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -144,15 +144,17 @@
         }
 
         val childModifier = Modifier.element(Bouncer.Elements.Content).fillMaxSize()
+        val isFullScreenUserSwitcherEnabled = viewModel.isUserSwitcherVisible
 
-        when (windowSizeClass.widthSizeClass) {
-            WindowWidthSizeClass.Expanded ->
+        when {
+            windowSizeClass.widthSizeClass == WindowWidthSizeClass.Expanded ->
                 SideBySide(
                     viewModel = viewModel,
                     dialogFactory = dialogFactory,
                     modifier = childModifier,
                 )
-            WindowWidthSizeClass.Medium ->
+            isFullScreenUserSwitcherEnabled &&
+                windowSizeClass.widthSizeClass == WindowWidthSizeClass.Medium ->
                 Stacked(
                     viewModel = viewModel,
                     dialogFactory = dialogFactory,
@@ -442,14 +444,22 @@
                 label = "offset",
             )
 
-        UserSwitcher(
-            viewModel = viewModel,
-            modifier =
-                Modifier.fillMaxHeight().weight(1f).graphicsLayer {
-                    translationX = size.width * animatedOffset
-                    alpha = animatedAlpha(animatedOffset)
-                },
-        )
+        val userSwitcherModifier =
+            Modifier.fillMaxHeight().weight(1f).graphicsLayer {
+                translationX = size.width * animatedOffset
+                alpha = animatedAlpha(animatedOffset)
+            }
+        if (viewModel.isUserSwitcherVisible) {
+            UserSwitcher(
+                viewModel = viewModel,
+                modifier = userSwitcherModifier,
+            )
+        } else {
+            Box(
+                modifier = userSwitcherModifier,
+            )
+        }
+
         Box(
             modifier =
                 Modifier.fillMaxHeight().weight(1f).graphicsLayer {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index c3a3752..ee310ab 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -36,13 +36,14 @@
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.core.view.isVisible
 import com.android.compose.animation.scene.SceneScope
-import com.android.systemui.res.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.qualifiers.KeyguardRootView
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
+import com.android.systemui.res.R
 import com.android.systemui.scene.shared.model.Direction
+import com.android.systemui.scene.shared.model.Edge
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.scene.shared.model.UserAction
@@ -99,7 +100,9 @@
         return buildMap {
             up?.let { this[UserAction.Swipe(Direction.UP)] = SceneModel(up) }
             left?.let { this[UserAction.Swipe(Direction.LEFT)] = SceneModel(left) }
-            this[UserAction.Swipe(Direction.DOWN)] = SceneModel(SceneKey.Shade)
+            this[UserAction.Swipe(fromEdge = Edge.TOP, direction = Direction.DOWN)] =
+                SceneModel(SceneKey.QuickSettings)
+            this[UserAction.Swipe(direction = Direction.DOWN)] = SceneModel(SceneKey.Shade)
         }
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 1f9c3e6..a33eac5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -23,11 +23,13 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.qs.footer.ui.compose.QuickSettings
@@ -37,6 +39,7 @@
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.scene.shared.model.UserAction
 import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
 import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
@@ -98,12 +101,22 @@
                 .clickable(onClick = { viewModel.onContentClicked() })
                 .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)
     ) {
-        ExpandedShadeHeader(
-            viewModel = viewModel.shadeHeaderViewModel,
-            createTintedIconManager = createTintedIconManager,
-            createBatteryMeterViewController = createBatteryMeterViewController,
-            statusBarIconController = statusBarIconController,
-        )
+        when (LocalWindowSizeClass.current.widthSizeClass) {
+            WindowWidthSizeClass.Compact ->
+                ExpandedShadeHeader(
+                    viewModel = viewModel.shadeHeaderViewModel,
+                    createTintedIconManager = createTintedIconManager,
+                    createBatteryMeterViewController = createBatteryMeterViewController,
+                    statusBarIconController = statusBarIconController,
+                )
+            else ->
+                CollapsedShadeHeader(
+                    viewModel = viewModel.shadeHeaderViewModel,
+                    createTintedIconManager = createTintedIconManager,
+                    createBatteryMeterViewController = createBatteryMeterViewController,
+                    statusBarIconController = statusBarIconController,
+                )
+        }
         Spacer(modifier = Modifier.height(16.dp))
         QuickSettings()
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index 2ee461f..f35ea83 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -22,6 +22,7 @@
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.scene.shared.model.Direction
+import com.android.systemui.scene.shared.model.Edge
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.scene.shared.model.UserAction
@@ -41,7 +42,12 @@
     override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> =
         MutableStateFlow<Map<UserAction, SceneModel>>(
                 mapOf(
-                    UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade),
+                    UserAction.Swipe(
+                        pointerCount = 2,
+                        fromEdge = Edge.TOP,
+                        direction = Direction.DOWN,
+                    ) to SceneModel(SceneKey.QuickSettings),
+                    UserAction.Swipe(direction = Direction.DOWN) to SceneModel(SceneKey.Shade),
                 )
             )
             .asStateFlow()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index ef01266..2e93a09 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -35,15 +35,18 @@
 import androidx.compose.ui.input.pointer.motionEventSpy
 import androidx.compose.ui.input.pointer.pointerInput
 import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.Edge as SceneTransitionEdge
 import com.android.compose.animation.scene.ObservableTransitionState as SceneTransitionObservableTransitionState
 import com.android.compose.animation.scene.SceneKey as SceneTransitionSceneKey
 import com.android.compose.animation.scene.SceneTransitionLayout
 import com.android.compose.animation.scene.SceneTransitionLayoutState
 import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
 import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction
 import com.android.compose.animation.scene.observableTransitionState
 import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
 import com.android.systemui.scene.shared.model.Direction
+import com.android.systemui.scene.shared.model.Edge
 import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
@@ -180,12 +183,24 @@
 private fun UserAction.toTransitionUserAction(): SceneTransitionUserAction {
     return when (this) {
         is UserAction.Swipe ->
-            when (this.direction) {
-                Direction.LEFT -> Swipe.Left
-                Direction.UP -> Swipe.Up
-                Direction.RIGHT -> Swipe.Right
-                Direction.DOWN -> Swipe.Down
-            }
+            Swipe(
+                pointerCount = pointerCount,
+                fromEdge =
+                    when (this.fromEdge) {
+                        null -> null
+                        Edge.LEFT -> SceneTransitionEdge.Left
+                        Edge.TOP -> SceneTransitionEdge.Top
+                        Edge.RIGHT -> SceneTransitionEdge.Right
+                        Edge.BOTTOM -> SceneTransitionEdge.Bottom
+                    },
+                direction =
+                    when (this.direction) {
+                        Direction.LEFT -> SwipeDirection.Left
+                        Direction.UP -> SwipeDirection.Up
+                        Direction.RIGHT -> SwipeDirection.Right
+                        Direction.DOWN -> SwipeDirection.Down
+                    }
+            )
         is UserAction.Back -> Back
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index 6629a25..591fa76 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -30,6 +30,7 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.layout.widthIn
+import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.derivedStateOf
@@ -50,6 +51,7 @@
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.ValueKey
 import com.android.compose.animation.scene.animateSharedFloatAsState
+import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.settingslib.Utils
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
@@ -98,12 +100,12 @@
             ShadeHeader.Keys.transitionProgress,
             ShadeHeader.Elements.FormatPlaceholder
         )
-    val useExpandedFormat by
-        remember(formatProgress) { derivedStateOf { formatProgress.value > 0.5f } }
 
     val cutoutWidth = LocalDisplayCutout.current.width()
     val cutoutLocation = LocalDisplayCutout.current.location
 
+    val useExpandedFormat = formatProgress.value > 0.5f || cutoutLocation != CutoutLocation.CENTER
+
     // This layout assumes it is globally positioned at (0, 0) and is the
     // same size as the screen.
     Layout(
@@ -131,6 +133,14 @@
                 {
                     Row(horizontalArrangement = Arrangement.End) {
                         SystemIconContainer {
+                            when (LocalWindowSizeClass.current.widthSizeClass) {
+                                WindowWidthSizeClass.Medium,
+                                WindowWidthSizeClass.Expanded ->
+                                    ShadeCarrierGroup(
+                                        viewModel = viewModel,
+                                        modifier = Modifier.align(Alignment.CenterVertically),
+                                    )
+                            }
                             StatusIcons(
                                 viewModel = viewModel,
                                 createTintedIconManager = createTintedIconManager,
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-af/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-af/strings.xml
index f8b843b..4c2c627 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-af/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Verstek vir digitaal"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-am/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-am/strings.xml
index f8b843b..847d7a5 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-am/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ዲጂታል ነባሪ"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-ar/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-ar/strings.xml
index f8b843b..57d1612 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-ar/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"رقمية تلقائية"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-as/strings.xml b/packages/SystemUI/customization/res/values-as/strings.xml
new file mode 100644
index 0000000..2f3b64b
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-as/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ডিজিটেল ডিফ’ল্ট"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-az/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-az/strings.xml
index f8b843b..eb52f95 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-az/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Rəqəmsal defolt"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml
index f8b843b..90e6678 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitalni podrazumevani"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-be/strings.xml b/packages/SystemUI/customization/res/values-be/strings.xml
new file mode 100644
index 0000000..f327da2
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-be/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"электронны, стандартны шрыфт"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-bg/strings.xml b/packages/SystemUI/customization/res/values-bg/strings.xml
new file mode 100644
index 0000000..6e3754a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-bg/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Стандартно дигитално"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-bn/strings.xml b/packages/SystemUI/customization/res/values-bn/strings.xml
new file mode 100644
index 0000000..adf1256
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-bn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ডিজিটাল ডিফল্ট"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-bs/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-bs/strings.xml
index f8b843b..8de04ab 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-bs/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitalno zadano"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-ca/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-ca/strings.xml
index f8b843b..967bb3f 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-ca/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital predeterminat"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-cs/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-cs/strings.xml
index f8b843b..45da4d7 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-cs/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitální výchozí"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-da/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-da/strings.xml
index f8b843b..3ffaa8b 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-da/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Standard (digital)"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-de/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-de/strings.xml
index f8b843b..64f95e0 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-de/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital (Standard)"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-el/strings.xml b/packages/SystemUI/customization/res/values-el/strings.xml
new file mode 100644
index 0000000..57134b5
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-el/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Ψηφιακή προεπιλογή"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-en-rAU/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-en-rAU/strings.xml
index f8b843b..a6110d5 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-en-rAU/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-en-rCA/strings.xml
similarity index 61%
rename from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
rename to packages/SystemUI/customization/res/values-en-rCA/strings.xml
index f8b843b..79919c0 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-en-rCA/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for clock_default_description (5309401440896597541) -->
+    <skip />
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-en-rGB/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-en-rGB/strings.xml
index f8b843b..a6110d5 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-en-rGB/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-en-rIN/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-en-rIN/strings.xml
index f8b843b..a6110d5 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-en-rIN/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-en-rXC/strings.xml b/packages/SystemUI/customization/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..7c540da
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-en-rXC/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‏‎Digital default‎‏‎‎‏‎"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-es-rUS/strings.xml b/packages/SystemUI/customization/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..59be786
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-es-rUS/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Configuración predeterminada digital"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-es/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-es/strings.xml
index f8b843b..03ef0e5 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-es/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital predeterminada"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-et/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-et/strings.xml
index f8b843b..fec793e 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-et/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitaalne vaikimisi"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-eu/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-eu/strings.xml
index f8b843b..a70c808 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-eu/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital lehenetsia"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-fa/strings.xml b/packages/SystemUI/customization/res/values-fa/strings.xml
new file mode 100644
index 0000000..6426d51
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-fa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"دیجیتال پیش‌فرض"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-fi/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-fi/strings.xml
index f8b843b..9b19373 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-fi/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitaalinen (oletus)"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-fr-rCA/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-fr-rCA/strings.xml
index f8b843b..bbd1208 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-fr-rCA/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Numérique, par défaut"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-fr/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-fr/strings.xml
index f8b843b..5579a42 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-fr/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Numérique par défaut"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-gl/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-gl/strings.xml
index f8b843b..2da93c6 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-gl/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Predeterminada dixital"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-gu/strings.xml b/packages/SystemUI/customization/res/values-gu/strings.xml
new file mode 100644
index 0000000..c578a2e
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-gu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ડિજિટલ ડિફૉલ્ટ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-hi/strings.xml b/packages/SystemUI/customization/res/values-hi/strings.xml
new file mode 100644
index 0000000..6080f80
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-hi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डिफ़ॉल्ट"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-hr/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-hr/strings.xml
index f8b843b..0a1440f 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-hr/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitalni zadani"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-hu/strings.xml b/packages/SystemUI/customization/res/values-hu/strings.xml
new file mode 100644
index 0000000..32618a8
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-hu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitális, alapértelmezett"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-hy/strings.xml b/packages/SystemUI/customization/res/values-hy/strings.xml
new file mode 100644
index 0000000..d45afbf
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-hy/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Թվային, կանխադրված"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-in/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-in/strings.xml
index f8b843b..a6110d5 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-in/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-is/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-is/strings.xml
index f8b843b..5a370d6 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-is/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Stafræn, sjálfgefið"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-it/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-it/strings.xml
index f8b843b..2a5087d 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-it/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitale - predefinito"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-iw/strings.xml b/packages/SystemUI/customization/res/values-iw/strings.xml
new file mode 100644
index 0000000..ddd28f2
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-iw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"דיגיטלי ברירת מחדל"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ja/strings.xml b/packages/SystemUI/customization/res/values-ja/strings.xml
new file mode 100644
index 0000000..744604a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ja/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"デジタル デフォルト"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ka/strings.xml b/packages/SystemUI/customization/res/values-ka/strings.xml
new file mode 100644
index 0000000..88ba1df
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ka/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ციფრული ნაგულისხმევი"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-kk/strings.xml b/packages/SystemUI/customization/res/values-kk/strings.xml
new file mode 100644
index 0000000..9ee6522
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-kk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Цифрлық әдепкі"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-km/strings.xml b/packages/SystemUI/customization/res/values-km/strings.xml
new file mode 100644
index 0000000..bbc438a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-km/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"លំនាំដើមឌីជីថល"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-kn/strings.xml b/packages/SystemUI/customization/res/values-kn/strings.xml
new file mode 100644
index 0000000..e67319d
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-kn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ಡಿಜಿಟಲ್ ಡೀಫಾಲ್ಟ್"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-ko/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-ko/strings.xml
index f8b843b..fa9103b 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-ko/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"디지털 기본"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ky/strings.xml b/packages/SystemUI/customization/res/values-ky/strings.xml
new file mode 100644
index 0000000..76cc5e2
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ky/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Демейки санариптик"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-lo/strings.xml b/packages/SystemUI/customization/res/values-lo/strings.xml
new file mode 100644
index 0000000..28f5000
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-lo/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ດິຈິຕອນຕາມຄ່າເລີ່ມຕົ້ນ"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-lt/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-lt/strings.xml
index f8b843b..2fe7315 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-lt/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Skaitmeninis numatytasis"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-lv/strings.xml b/packages/SystemUI/customization/res/values-lv/strings.xml
new file mode 100644
index 0000000..e0b904a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-lv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitālais pulkstenis — noklusējums"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-mk/strings.xml b/packages/SystemUI/customization/res/values-mk/strings.xml
new file mode 100644
index 0000000..9b95a6e
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-mk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Дигитален стандарден приказ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ml/strings.xml b/packages/SystemUI/customization/res/values-ml/strings.xml
new file mode 100644
index 0000000..7f6be8a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ml/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ഡിജിറ്റൽ ഡിഫോൾട്ട്"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-mn/strings.xml b/packages/SystemUI/customization/res/values-mn/strings.xml
new file mode 100644
index 0000000..38369b6
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-mn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Дижитал өгөгдмөл"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-mr/strings.xml b/packages/SystemUI/customization/res/values-mr/strings.xml
new file mode 100644
index 0000000..821ff10
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-mr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डीफॉल्टसह क्लॉक फेस"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-ms/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-ms/strings.xml
index f8b843b..2f61b47 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-ms/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital lalai"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-my/strings.xml b/packages/SystemUI/customization/res/values-my/strings.xml
new file mode 100644
index 0000000..3d137eb
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-my/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ဒစ်ဂျစ်တယ်နာရီ မူရင်း"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-nb/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-nb/strings.xml
index f8b843b..6eb4373 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-nb/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital – standard"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ne/strings.xml b/packages/SystemUI/customization/res/values-ne/strings.xml
new file mode 100644
index 0000000..c5b0877
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ne/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डिफल्ट"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-nl/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-nl/strings.xml
index f8b843b..4f46ab8 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-nl/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Standaard digitaal"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-or/strings.xml b/packages/SystemUI/customization/res/values-or/strings.xml
new file mode 100644
index 0000000..a74017f
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-or/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ଡିଜିଟାଲ ଡିଫଲ୍ଟ"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-pa/strings.xml b/packages/SystemUI/customization/res/values-pa/strings.xml
new file mode 100644
index 0000000..a77661a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-pa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ਡਿਜੀਟਲ ਡਿਫਾਲਟ"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-pl/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-pl/strings.xml
index f8b843b..6f5b6f2 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-pl/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Cyfrowa domyślna"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-pt-rPT/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-pt-rPT/strings.xml
index f8b843b..c6c3cc0 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-pt-rPT/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Predefinição digital"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-pt/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-pt/strings.xml
index f8b843b..bbe4355 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-pt/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital padrão"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-ro/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-ro/strings.xml
index f8b843b..ef163e9 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-ro/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Implicit digital"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ru/strings.xml b/packages/SystemUI/customization/res/values-ru/strings.xml
new file mode 100644
index 0000000..5ee928e
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ru/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Цифровые часы, стандартный"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-si/strings.xml b/packages/SystemUI/customization/res/values-si/strings.xml
new file mode 100644
index 0000000..caf9610
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-si/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ඩිජිටල් පෙරනිමිය"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-sk/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-sk/strings.xml
index f8b843b..1843f97 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-sk/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitálne predvolené"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-sl/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-sl/strings.xml
index f8b843b..12df66f 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-sl/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digitalna (privzeta)"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-sq/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-sq/strings.xml
index f8b843b..1fc9f25 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-sq/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Dixhitale e parazgjedhur"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sr/strings.xml b/packages/SystemUI/customization/res/values-sr/strings.xml
new file mode 100644
index 0000000..6b127c9
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Дигитални подразумевани"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-sv/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-sv/strings.xml
index f8b843b..84ad25c 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-sv/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital standard"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-sw/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-sw/strings.xml
index f8b843b..e2ec3de 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-sw/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Dijitali chaguomsingi"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-sw400dp/dimens.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-sw400dp/dimens.xml
index f8b843b..3c9e078 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-sw400dp/dimens.xml
@@ -1,5 +1,6 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2023, 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.
@@ -12,11 +13,8 @@
  * 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.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+*/
+-->
+<resources>
+    <dimen name="presentation_clock_text_size">170dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-ta/strings.xml b/packages/SystemUI/customization/res/values-ta/strings.xml
new file mode 100644
index 0000000..f4eea07
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-ta/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"டிஜிட்டல் இயல்பு"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-te/strings.xml b/packages/SystemUI/customization/res/values-te/strings.xml
new file mode 100644
index 0000000..c7c77d5
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-te/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"డిజిటల్ ఆటోమేటిక్ సెట్టింగ్"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-th/strings.xml b/packages/SystemUI/customization/res/values-th/strings.xml
new file mode 100644
index 0000000..61d880e
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-th/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ดิจิทัลแบบเริ่มต้น"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-tl/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-tl/strings.xml
index f8b843b..a3484a7 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-tl/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Digital na default"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-tr/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-tr/strings.xml
index f8b843b..a90e985 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-tr/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Dijital varsayılan"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-uk/strings.xml b/packages/SystemUI/customization/res/values-uk/strings.xml
new file mode 100644
index 0000000..ee9b77b
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-uk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Цифровий, стандартний"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-ur/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-ur/strings.xml
index f8b843b..06a6a7c 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-ur/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"ڈیجیٹل ڈیفالٹ"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-uz/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-uz/strings.xml
index f8b843b..6b31b04 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-uz/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Raqamli soat, standart"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-vi/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-vi/strings.xml
index f8b843b..830b6e2 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-vi/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Mặt số mặc định"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-zh-rCN/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-zh-rCN/strings.xml
index f8b843b..747567e 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-zh-rCN/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"默认数字"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-zh-rHK/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-zh-rHK/strings.xml
index f8b843b..c19cc68 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-zh-rHK/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"數碼時鐘 (預設)"</string>
+</resources>
\ No newline at end of file
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/packages/SystemUI/customization/res/values-zh-rTW/strings.xml
similarity index 60%
copy from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
copy to packages/SystemUI/customization/res/values-zh-rTW/strings.xml
index f8b843b..6fcd313 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/packages/SystemUI/customization/res/values-zh-rTW/strings.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, 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.
@@ -13,10 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"數位預設"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-zu/strings.xml b/packages/SystemUI/customization/res/values-zu/strings.xml
new file mode 100644
index 0000000..c87c250a
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-zu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+        <string name="clock_default_description" msgid="5309401440896597541">"Okuzenzakalelayo kwedijithali"</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values/dimens.xml b/packages/SystemUI/customization/res/values/dimens.xml
index 8eb8132..c574d1f 100644
--- a/packages/SystemUI/customization/res/values/dimens.xml
+++ b/packages/SystemUI/customization/res/values/dimens.xml
@@ -17,6 +17,7 @@
 -->
 <resources>
     <!-- Clock maximum font size (dp is intentional, to prevent any further scaling) -->
+    <dimen name="presentation_clock_text_size">50dp</dimen>
     <dimen name="large_clock_text_size">150dp</dimen>
     <dimen name="small_clock_text_size">86dp</dimen>
 
diff --git a/packages/SystemUI/customization/res/values/strings.xml b/packages/SystemUI/customization/res/values/strings.xml
new file mode 100644
index 0000000..897c842
--- /dev/null
+++ b/packages/SystemUI/customization/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- default clock face name [CHAR LIMIT=NONE]-->
+    <string name="clock_default_name">Default</string>
+
+    <!-- default clock face description [CHAR LIMIT=NONE]-->
+    <string name="clock_default_description">Digital default</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index b28920c..b076b2c 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -65,7 +65,13 @@
     protected var onSecondaryDisplay: Boolean = false
 
     override val events: DefaultClockEvents
-    override val config = ClockConfig(DEFAULT_CLOCK_ID)
+    override val config: ClockConfig by lazy {
+        ClockConfig(
+            DEFAULT_CLOCK_ID,
+            resources.getString(R.string.clock_default_name),
+            resources.getString(R.string.clock_default_description)
+        )
+    }
 
     init {
         val parent = FrameLayout(ctx)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index 949641a..dd52e39 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -25,7 +25,6 @@
 import com.android.systemui.plugins.ClockSettings
 
 private val TAG = DefaultClockProvider::class.simpleName
-const val DEFAULT_CLOCK_NAME = "Default Clock"
 const val DEFAULT_CLOCK_ID = "DEFAULT"
 
 /** Provides the default system clock */
@@ -35,8 +34,7 @@
     val resources: Resources,
     val hasStepClockAnimation: Boolean = false
 ) : ClockProvider {
-    override fun getClocks(): List<ClockMetadata> =
-        listOf(ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME))
+    override fun getClocks(): List<ClockMetadata> = listOf(ClockMetadata(DEFAULT_CLOCK_ID))
 
     override fun createClock(settings: ClockSettings): ClockController {
         if (settings.clockId != DEFAULT_CLOCK_ID) {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index e2f4793..485c27e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -192,15 +192,18 @@
 /** Some data about a clock design */
 data class ClockMetadata(
     val clockId: ClockId,
-    val name: String,
-) {
-    constructor(clockId: ClockId) : this(clockId, clockId) {}
-}
+)
 
 /** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
 data class ClockConfig(
     val id: String,
 
+    /** Localized name of the clock */
+    val name: String,
+
+    /** Localized accessibility description for the clock */
+    val description: String,
+
     /** Transition to AOD should move smartspace like large clock instead of small clock */
     val useAlternateSmartspaceAODTransition: Boolean = false,
 
diff --git a/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml b/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml
new file mode 100644
index 0000000..2187352
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 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.
+  ~
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:sysui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/alternate_bouncer"
+    android:focusable="true"
+    android:clickable="true"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.systemui.scrim.ScrimView
+        android:id="@+id/alternate_bouncer_scrim"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:importantForAccessibility="no"
+        sysui:ignoreRightInset="true"
+    />
+</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml
index 593f507f..f68ab81 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml
@@ -16,22 +16,30 @@
 */
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/presentation"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <com.android.keyguard.KeyguardStatusView
         android:id="@+id/clock"
-        android:layout_width="410dp"
-        android:layout_height="wrap_content"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
         android:layout_gravity="center"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintDimensionRatio="1:1"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
 
         <include
             android:id="@+id/keyguard_clock_container"
             layout="@layout/keyguard_clock_switch"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"/>
     </com.android.keyguard.KeyguardStatusView>
 
-</FrameLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 69f533c..67b4e4b 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -125,7 +125,7 @@
     <string name="clock_title_bubble" msgid="2204559396790593213">"বাবল"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"অ্যানালগ"</string>
     <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"চালিয়ে যেতে আপনার ডিভাইস আনলক করুন"</string>
-    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"পরে ইনস্টল আপডেট করতে পিন লিখুন"</string>
+    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"পরে আপডেট ইনস্টল করতে পিন লিখুন"</string>
     <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"পরে আপডেট ইনস্টল করতে পাসওয়ার্ড লিখুন"</string>
     <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"পরে আপডেট ইনস্টল করতে প্যাটার্ন আঁকুন"</string>
     <string name="kg_prompt_after_update_pin" msgid="7051709651908643013">"ডিভাইস আপডেট করা হয়েছে। চালিয়ে যেতে পিন লিখুন।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index e075d85..573638b 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -125,9 +125,9 @@
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bublina"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analogové"</string>
     <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Pokud chcete pokračovat, odemkněte zařízení"</string>
-    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"Pokud aktualizaci chcete nainstalovat později, zadejte PIN"</string>
-    <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"Pokud aktualizaci chcete nainstalovat později, zadejte heslo"</string>
-    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Pokud aktualizaci chcete nainstalovat později, zadejte gesto"</string>
+    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"Zadejte PIN a aktualizaci nainstalujte později"</string>
+    <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"Zadejte heslo a aktualizaci nainstalujte později"</string>
+    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Zadejte gesto a aktualizaci nainstalujte později"</string>
     <string name="kg_prompt_after_update_pin" msgid="7051709651908643013">"Zařízení bylo aktualizováno. Pokud chcete pokračovat, zadejte PIN."</string>
     <string name="kg_prompt_after_update_password" msgid="153703052501352094">"Zařízení bylo aktualizováno. Pokud chcete pokračovat, zadejte heslo."</string>
     <string name="kg_prompt_after_update_pattern" msgid="1484084551298241992">"Zařízení bylo aktualizováno. Pokud chcete pokračovat, zadejte gesto."</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 117f7a9..5c5f264 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -125,9 +125,9 @@
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
     <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Gerät entsperren, um fortzufahren"</string>
-    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"Gib deine PIN ein, um das Update später zu installieren"</string>
-    <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"Gib dein Passwort ein, um das Update später zu installieren"</string>
-    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Zeichne dein Muster, um das Update später zu installieren"</string>
+    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"PIN eingeben, um Update später zu installieren"</string>
+    <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"Passwort eingeben, um Update später zu installieren"</string>
+    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Muster zeichnen, um Update später zu installieren"</string>
     <string name="kg_prompt_after_update_pin" msgid="7051709651908643013">"Gerät aktualisiert. Gib deine PIN ein, um fortzufahren."</string>
     <string name="kg_prompt_after_update_password" msgid="153703052501352094">"Gerät aktualisiert. Gib dein Passwort ein, um fortzufahren."</string>
     <string name="kg_prompt_after_update_pattern" msgid="1484084551298241992">"Gerät aktualisiert. Zeichne dein Muster, um fortzufahren."</string>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index cd7637c..3a01da5 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -125,9 +125,9 @@
     <string name="clock_title_bubble" msgid="2204559396790593213">"Συννεφάκι"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Αναλογικό"</string>
     <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Ξεκλειδώστε τη συσκευή σας για να συνεχίσετε"</string>
-    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"Εισαγάγετε το PIN για να εγκαταστήσετε την ενημέρωση αργότερα"</string>
+    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"Εισαγωγή PIN για εγκατάσταση ενημέρωσης αργότερα"</string>
     <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"Εισαγ. τον κωδ. πρόσβασης για να εγκαταστήσετε την ενημέρωση αργότερα"</string>
-    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Σχεδιάστε το μοτίβο για να εγκαταστήσετε την ενημέρωση αργότερα"</string>
+    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Σχεδιάστε το μοτίβο για εγκατάσταση της ενημέρωσης αργότερα"</string>
     <string name="kg_prompt_after_update_pin" msgid="7051709651908643013">"Η συσκευή ενημερώθηκε. Εισαγάγετε το PIN για να συνεχίσετε."</string>
     <string name="kg_prompt_after_update_password" msgid="153703052501352094">"Η συσκευή ενημερώθηκε. Εισαγάγ. τον κωδ. πρόσβασης για να συνεχίσετε."</string>
     <string name="kg_prompt_after_update_pattern" msgid="1484084551298241992">"Η συσκευή ενημερώθηκε. Σχεδιάστε το μοτίβο για να συνεχίσετε."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 4815815..ae3f04a 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -125,9 +125,9 @@
     <string name="clock_title_bubble" msgid="2204559396790593213">"حباب"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"آنالوگ"</string>
     <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"برای ادامه، قفل دستگاهتان را باز کنید"</string>
-    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"برای نصب به‌روزرسانی در فرصتی دیگر، پین را وارد کنید"</string>
-    <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"برای نصب به‌روزرسانی در فرصتی دیگر، گذرواژه را وارد کنید"</string>
-    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"برای نصب به‌روزرسانی در فرصتی دیگر، الگو را وارد کنید"</string>
+    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"پین را وارد کنید و به‌روزرسانی را در فرصتی دیگر انجام دهید"</string>
+    <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"گذرواژه را وارد کنید و به‌روزرسانی را در فرصتی دیگر انجام دهید"</string>
+    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"الگو را وارد کنید و به‌روزرسانی را در فرصتی دیگر انجام دهید"</string>
     <string name="kg_prompt_after_update_pin" msgid="7051709651908643013">"دستگاه به‌روز شد. برای ادامه، پین را وارد کنید."</string>
     <string name="kg_prompt_after_update_password" msgid="153703052501352094">"دستگاه به‌روز شد. برای ادامه، گذرواژه را وارد کنید."</string>
     <string name="kg_prompt_after_update_pattern" msgid="1484084551298241992">"دستگاه به‌روز شد. برای ادامه، الگو را وارد کنید."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 02d41d8..050df99 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -127,7 +127,7 @@
     <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Jatka avaamalla laitteen lukitus"</string>
     <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"Jos haluat asentaa päivityksen myöhemmin, lisää PIN-koodi"</string>
     <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"Jos haluat asentaa päivityksen myöhemmin, lisää salasana"</string>
-    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Jos haluat asentaa päivityksen myöhemmin, piirrä kuvio"</string>
+    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Salli päivitys myöhemmin piirtämällä kuvio"</string>
     <string name="kg_prompt_after_update_pin" msgid="7051709651908643013">"Laite päivitetty. Jatka lisäämällä PIN-koodi."</string>
     <string name="kg_prompt_after_update_password" msgid="153703052501352094">"Laite päivitetty. Jatka lisäämällä salasana."</string>
     <string name="kg_prompt_after_update_pattern" msgid="1484084551298241992">"Laite päivitetty. Jatka piirtämällä kuvio."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index e5be788..4309b56 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -127,7 +127,7 @@
     <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Deblochează dispozitivul pentru a continua"</string>
     <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"Introdu codul PIN pentru a instala actualizarea mai târziu"</string>
     <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"Introdu parola pentru a instala actualizarea mai târziu"</string>
-    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Desenează modelul pentru a instala actualizarea mai târziu"</string>
+    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"Desenează pentru a instala actualizarea mai târziu"</string>
     <string name="kg_prompt_after_update_pin" msgid="7051709651908643013">"Dispozitivul s-a actualizat. Introdu codul PIN pentru a continua."</string>
     <string name="kg_prompt_after_update_password" msgid="153703052501352094">"Dispozitivul s-a actualizat. Introdu parola pentru a continua."</string>
     <string name="kg_prompt_after_update_pattern" msgid="1484084551298241992">"Dispozitivul s-a actualizat. Desenează modelul pentru a continua."</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 59261a3..4c65832 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -125,9 +125,9 @@
     <string name="clock_title_bubble" msgid="2204559396790593213">"泡泡"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"指针"</string>
     <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"解锁设备才能继续操作"</string>
-    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"需要输入 PIN 码才能稍后安装更新"</string>
-    <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"需要输入密码才能稍后安装更新"</string>
-    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"需要绘制解锁图案才能稍后安装更新"</string>
+    <string name="kg_prompt_unattended_update_pin" msgid="5979434876768801873">"请输入 PIN 码,系统稍后会安装更新"</string>
+    <string name="kg_prompt_unattended_update_password" msgid="8805664437604967210">"请输入密码,系统稍后会安装更新"</string>
+    <string name="kg_prompt_unattended_update_pattern" msgid="8580479377489546091">"请绘制解锁图案,系统稍后会安装更新"</string>
     <string name="kg_prompt_after_update_pin" msgid="7051709651908643013">"设备已更新。您需要输入 PIN 码才能继续。"</string>
     <string name="kg_prompt_after_update_password" msgid="153703052501352094">"设备已更新。您需要输入密码才能继续。"</string>
     <string name="kg_prompt_after_update_pattern" msgid="1484084551298241992">"设备已更新。您需要绘制解锁图案才能继续。"</string>
diff --git a/packages/SystemUI/res/layout/bluetooth_device_item.xml b/packages/SystemUI/res/layout/bluetooth_device_item.xml
index 1c7e997..6d77943 100644
--- a/packages/SystemUI/res/layout/bluetooth_device_item.xml
+++ b/packages/SystemUI/res/layout/bluetooth_device_item.xml
@@ -27,7 +27,6 @@
 
     <ImageView
         android:id="@+id/bluetooth_device_icon"
-        android:contentDescription="@string/accessibility_bluetooth_device_icon"
         android:layout_width="24dp"
         android:layout_height="24dp"
         app:layout_constraintStart_toStartOf="parent"
@@ -39,8 +38,12 @@
         android:layout_width="0dp"
         android:id="@+id/bluetooth_device_name"
         style="@style/BluetoothTileDialog.DeviceName"
+        android:textDirection="locale"
+        android:textAlignment="gravity"
         android:paddingStart="20dp"
         android:paddingTop="10dp"
+        android:maxLines="1"
+        android:ellipsize="end"
         app:layout_constraintWidth_percent="0.7"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintStart_toEndOf="@+id/bluetooth_device_icon"
@@ -55,6 +58,8 @@
         style="@style/BluetoothTileDialog.DeviceSummary"
         android:paddingStart="20dp"
         android:paddingBottom="10dp"
+        android:maxLines="1"
+        android:ellipsize="end"
         app:layout_constraintWidth_percent="0.7"
         app:layout_constraintTop_toBottomOf="@+id/bluetooth_device_name"
         app:layout_constraintStart_toEndOf="@+id/bluetooth_device_icon"
@@ -66,6 +71,7 @@
         android:id="@+id/gear_icon"
         android:layout_width="0dp"
         android:layout_height="0dp"
+        android:contentDescription="@string/accessibility_bluetooth_device_settings_gear"
         app:layout_constraintStart_toEndOf="@+id/bluetooth_device_name"
         app:layout_constraintEnd_toEndOf="@+id/gear_icon_image"
         app:layout_constraintTop_toTopOf="parent"
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index 16aeb95..5d986e0 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -27,6 +27,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:paddingTop="24dp"
+        android:maxLines="1"
         android:ellipsize="end"
         android:gravity="center_vertical|center_horizontal"
         android:text="@string/quick_settings_bluetooth_label"
@@ -58,9 +59,12 @@
         style="@style/BluetoothTileDialog.Device"
         android:layout_width="0dp"
         android:layout_height="64dp"
+        android:maxLines="1"
+        android:ellipsize="end"
         android:gravity="center_vertical"
         android:layout_marginTop="4dp"
         android:text="@string/turn_on_bluetooth"
+        android:clickable="false"
         android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
         android:textSize="16sp"
         app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
@@ -84,53 +88,17 @@
         app:layout_constraintStart_toEndOf="@+id/bluetooth_toggle_title"
         app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle" />
 
-    <androidx.constraintlayout.widget.Group
-        android:id="@+id/pair_new_device_layout_group"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:visibility="gone"
-        app:constraint_referenced_ids="ic_add,pair_new_device_text" />
-
-    <ImageView
-        android:id="@+id/ic_add"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_marginStart="36dp"
-        android:gravity="center_vertical"
-        android:importantForAccessibility="no"
-        android:src="@drawable/ic_add"
-        app:layout_constraintBottom_toTopOf="@id/device_list"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/pair_new_device_text"
-        app:layout_constraintTop_toBottomOf="@id/bluetooth_toggle_title"
-        android:tint="?android:attr/textColorPrimary" />
-
-    <TextView
-        android:id="@+id/pair_new_device_text"
-        style="@style/BluetoothTileDialog.Device"
-        android:layout_width="0dp"
-        android:layout_height="@dimen/bluetooth_dialog_device_height"
-        android:gravity="center_vertical"
-        android:layout_marginStart="0dp"
-        android:paddingStart="20dp"
-        android:text="@string/pair_new_bluetooth_devices"
-        android:textSize="14sp"
-        android:textAppearance="@style/TextAppearance.Dialog.Title"
-        app:layout_constraintBottom_toTopOf="@id/device_list"
-        app:layout_constraintStart_toEndOf="@+id/ic_add"
-        app:layout_constraintTop_toBottomOf="@id/bluetooth_toggle_title"
-        app:layout_constraintEnd_toEndOf="parent" />
-
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/device_list"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_marginTop="20dp"
         android:nestedScrollingEnabled="false"
         android:overScrollMode="never"
         android:scrollbars="vertical"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/pair_new_device_text"
+        app:layout_constraintTop_toBottomOf="@id/bluetooth_toggle"
         app:layout_constraintBottom_toTopOf="@+id/see_all_text" />
 
     <androidx.constraintlayout.widget.Group
@@ -148,7 +116,7 @@
         android:importantForAccessibility="no"
         android:gravity="center_vertical"
         android:src="@drawable/ic_arrow_forward"
-        app:layout_constraintBottom_toTopOf="@+id/done_button"
+        app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toStartOf="@id/see_all_text"
         app:layout_constraintTop_toBottomOf="@id/device_list" />
@@ -157,18 +125,59 @@
         android:id="@+id/see_all_text"
         style="@style/BluetoothTileDialog.Device"
         android:layout_width="0dp"
-        android:layout_height="@dimen/bluetooth_dialog_device_height"
+        android:layout_height="64dp"
+        android:maxLines="1"
+        android:ellipsize="end"
         android:gravity="center_vertical"
         android:layout_marginStart="0dp"
         android:paddingStart="20dp"
         android:text="@string/see_all_bluetooth_devices"
         android:textSize="14sp"
         android:textAppearance="@style/TextAppearance.Dialog.Title"
-        app:layout_constraintBottom_toTopOf="@+id/done_button"
+        app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
         app:layout_constraintStart_toEndOf="@+id/ic_arrow"
         app:layout_constraintTop_toBottomOf="@id/device_list"
         app:layout_constraintEnd_toEndOf="parent" />
 
+    <androidx.constraintlayout.widget.Group
+        android:id="@+id/pair_new_device_layout_group"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        app:constraint_referenced_ids="ic_add,pair_new_device_text" />
+
+    <ImageView
+        android:id="@+id/ic_add"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginStart="36dp"
+        android:gravity="center_vertical"
+        android:importantForAccessibility="no"
+        android:src="@drawable/ic_add"
+        app:layout_constraintBottom_toTopOf="@id/done_button"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/pair_new_device_text"
+        app:layout_constraintTop_toBottomOf="@id/see_all_text"
+        android:tint="?android:attr/textColorPrimary" />
+
+    <TextView
+        android:id="@+id/pair_new_device_text"
+        style="@style/BluetoothTileDialog.Device"
+        android:layout_width="0dp"
+        android:layout_height="64dp"
+        android:maxLines="1"
+        android:ellipsize="end"
+        android:gravity="center_vertical"
+        android:layout_marginStart="0dp"
+        android:paddingStart="20dp"
+        android:text="@string/pair_new_bluetooth_devices"
+        android:textSize="14sp"
+        android:textAppearance="@style/TextAppearance.Dialog.Title"
+        app:layout_constraintBottom_toTopOf="@id/done_button"
+        app:layout_constraintStart_toEndOf="@+id/ic_add"
+        app:layout_constraintTop_toBottomOf="@id/see_all_text"
+        app:layout_constraintEnd_toEndOf="parent" />
+
     <Button
         android:id="@+id/done_button"
         style="@style/Widget.Dialog.Button"
@@ -184,5 +193,5 @@
         android:text="@string/inline_done_button"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/see_all_text" />
+        app:layout_constraintTop_toBottomOf="@id/pair_new_device_text" />
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index ec006c5..16eba22 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -403,7 +403,7 @@
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:layout_gravity="start|center_vertical"
-                    android:orientation="vertical">
+                    android:orientation="horizontal">
                     <Button
                         android:id="@+id/apm_button"
                         android:layout_width="wrap_content"
@@ -414,12 +414,7 @@
                         style="@style/Widget.Dialog.Button.BorderButton"
                         android:clickable="true"
                         android:focusable="true"/>
-                </LinearLayout>
 
-                <RelativeLayout
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:gravity="center_vertical">
                     <Button
                         android:id="@+id/share_wifi_button"
                         android:layout_width="wrap_content"
@@ -430,8 +425,14 @@
                         android:ellipsize="end"
                         android:clickable="true"
                         android:focusable="true"
-                        android:layout_alignParentLeft="true"
                         android:visibility="gone"/>
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="16dp"
+                    android:layout_gravity="end|center_vertical">
                     <Button
                         android:id="@+id/done_button"
                         android:layout_width="wrap_content"
@@ -441,9 +442,8 @@
                         android:maxLines="1"
                         android:ellipsize="end"
                         android:clickable="true"
-                        android:focusable="true"
-                        android:layout_alignParentRight="true"/>
-                </RelativeLayout>
+                        android:focusable="true"/>
+                </LinearLayout>
             </LinearLayout>
 
         </LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index b00908f..c1bac31 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -15,7 +15,7 @@
   -->
 
 <!-- Extends Framelayout -->
-<com.android.systemui.statusbar.notification.row.FooterView
+<com.android.systemui.statusbar.notification.footer.ui.view.FooterView
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         android:layout_width="match_parent"
@@ -76,4 +76,4 @@
                 />
         </androidx.constraintlayout.widget.ConstraintLayout>
     </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
-</com.android.systemui.statusbar.notification.row.FooterView>
+</com.android.systemui.statusbar.notification.footer.ui.view.FooterView>
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index d4b73a4..acee425 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -130,6 +130,11 @@
         android:inflatedId="@+id/multi_shade"
         android:layout="@layout/multi_shade" />
 
+    <include layout="@layout/alternate_bouncer"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible" />
+
     <com.android.systemui.biometrics.AuthRippleView
         android:id="@+id/auth_ripple"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 937e97a..24846d9 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string>
     <string name="install_app" msgid="5066668100199613936">"Installeer app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Sinkroniseer wedersyds na eksterne skerm?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Sinkroniseer skerm wedersyds"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Maak toe"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoon en kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Onlangse appgebruik"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Sien onlangse toegang"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index de2fda4..23def28 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string>
     <string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ወደ ውጫዊ ማሳያ ይንጸባረቅ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ማሳያን አንጸባርቅ"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"አሰናብት"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ማይክሮፎን እና ካሜራ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"የቅርብ ጊዜ የመተግበሪያ አጠቃቀም"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"የቅርብ ጊዜ መዳረሻን አሳይ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 79b671c..80d63a2 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string>
     <string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"هل تريد بث محتوى جهازك على الشاشة الخارجية؟"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"بث المحتوى على الشاشة"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"إغلاق"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"الميكروفون والكاميرا"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"آخر استخدام في التطبيقات"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"عرض آخر استخدام في التطبيقات"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index ac30f18..c845773 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string>
     <string name="install_app" msgid="5066668100199613936">"এপ্‌টো ইনষ্টল কৰক"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"বাহ্যিক ডিছপ্লে’লৈ মিৰ’ৰ কৰিবনে?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ডিছপ্লে’ মিৰ’ৰ কৰক"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"অগ্ৰাহ্য কৰক"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"মাইক্ৰ’ফ’ন আৰু কেমেৰা"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"শেহতীয়া এপৰ ব্যৱহাৰ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"শেহতীয়া এক্সেছ চাওক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 3ca61dc..5aa26ba 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string>
     <string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Xarici displeyə əks etdirilsin?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Displeyi əks etdirin"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"İmtina edin"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon və kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Son tətbiq istifadəsi"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Son girişə baxın"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index b51d4b3..cd36884 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string>
     <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li da preslikate na spoljnji ekran?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavno koristila aplikacija"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Prikaži nedavni pristup"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 35a84b0..1b03c8b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string>
     <string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Адлюстраваць на знешнім дысплеі?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Адлюстраваць дысплэй"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Закрыць"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Мікрафон і камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Нядаўна выкарыстоўваліся праграмамі"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Паглядзець нядаўні доступ"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6b212e5..4ed1ad9 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се дублира ли на външния екран?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Огледално копиране на дисплея"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Отхвърляне"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Скорошно използване на приложението"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Вижте скорошния достъп"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 5b5ac73..426d38d 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string>
     <string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"এক্সটার্নাল ডিসপ্লে আয়না?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ডিসপ্লে দেখান"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"বাতিল করুন"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"মাইক্রোফোন ও ক্যামেরা"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"সম্প্রতি ব্যবহার করা অ্যাপ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"সাম্প্রতিক অ্যাক্সেস দেখুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 33330b7..4eed7b89 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string>
     <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Preslikati na vanjski ekran?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavno korištenje aplikacije"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Prikaži nedavni pristup"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 45bb342..b55a79a 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string>
     <string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vols replicar-ho a la pantalla externa?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Duplica la pantalla"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Ignora"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micròfon i càmera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ús recent de l\'aplicació"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Mostra l\'accés recent"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 0d7d23a..05b0419 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string>
     <string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Zrcadlit na externí displej?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Zrcadlit displej"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Zavřít"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon a fotoaparát"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedávné použití aplikacemi"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobrazit nedávný přístup"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 4f6b88e..5971034 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du spejle til ekstern skærm?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Spejl skærm"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Luk"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon og kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Seneste brug af apps"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se seneste adgang"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 07aa14f..c773f71 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string>
     <string name="install_app" msgid="5066668100199613936">"App installieren"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Auf externen Bildschirm spiegeln?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Bildschirm spiegeln"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Schließen"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon &amp; Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Kürzliche App-Nutzung"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Kürzliche Zugriffe ansehen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 2a8e51c..b6c95aa 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string>
     <string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Κατοπτρισμός σε εξωτερική οθόνη;"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Κατοπτρισμός οθόνης"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Παράβλεψη"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Μικρόφωνο και Κάμερα"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Πρόσφατη χρήση εφαρμογής"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Εμφάνιση πρόσφατης πρόσβασης"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 8647adb..6c2b230 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 8647adb..6c2b230 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 8647adb..6c2b230 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index d3ea858..52514d2 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Quieres duplicar a la pantalla externa?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Duplicar pantalla"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Descartar"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono y cámara"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso reciente en apps"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver accesos recientes"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 284fad4..4a3c064 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Replicar en pantalla externa?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Replicar pantalla"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Cerrar"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono y cámara"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso reciente en aplicaciones"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acceso reciente"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 2b79ee5..08b489d 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string>
     <string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kas peegeldada välisekraanile?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Ekraani peegeldamine"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Loobu"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon ja kaamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Rakenduste hiljutine kasutamine"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Kuva hiljutine juurdepääs"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 68698ea..19495bc 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -676,8 +676,8 @@
     <string name="group_system_go_back" msgid="8838454003680364227">"Atzera: itzuli aurreko egoerara (atzera egiteko botoia)"</string>
     <string name="group_system_access_home_screen" msgid="1857344316928441909">"Atzitu hasierako pantaila"</string>
     <string name="group_system_overview_open_apps" msgid="6897128761003265350">"Ikusi irekitako aplikazioen ikuspegi orokorra"</string>
-    <string name="group_system_cycle_forward" msgid="9202444850838205990">"Joan azken aplikazioetako batetik bestera (aurrera)"</string>
-    <string name="group_system_cycle_back" msgid="5163464503638229131">"Joan azken aplikazioetako batetik bestera (atzera)"</string>
+    <string name="group_system_cycle_forward" msgid="9202444850838205990">"Joan azkenaldian erabilitako aplikazio batetik bestera (aurrera)"</string>
+    <string name="group_system_cycle_back" msgid="5163464503638229131">"Joan azkenaldian erabilitako aplikazio batetik bestera (atzera)"</string>
     <string name="group_system_access_all_apps_search" msgid="488070738028991753">"Atzitu aplikazio guztien zerrenda eta bilatu (adibidez, bilatzeko aukeraren edo Exekutatzeko tresna aplikazioaren bidez)"</string>
     <string name="group_system_hide_reshow_taskbar" msgid="3809304065624351131">"Ezkutatu eta erakutsi (berriro) zereginen barra"</string>
     <string name="group_system_access_system_settings" msgid="7961639365383008053">"Atzitu sistemaren ezarpenak"</string>
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kanpoko pantailan islatu nahi duzu?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Islatu pantaila"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Baztertu"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofonoa eta kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Aplikazioen azken erabilera"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ikusi azkenaldiko sarbidea"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7199240..68f6c1d 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیش‌فرض یادداشت را در «تنظیمات» تنظیم کنید"</string>
     <string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"در نمایشگر خارجی پخش شود؟"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"بازتاباندن صفحه‌نمایش"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"بستن"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"میکروفون و دوربین"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"استفاده اخیر از برنامه"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"دیدن دسترسی اخیر"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 073ea60..934abad 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string>
     <string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Peilataanko ulkoiselle näytölle?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Peilaa näyttö"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Ohita"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoni ja kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Sovellusten viimeaikainen käyttö"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Katso viimeaikainen käyttö"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 52bcd76..fe90569 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer l\'écran sur un moniteur externe?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Fermer"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone et appareil photo"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applications"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Afficher l\'accès récent"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4362d3c..27a4bb6 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirroring sur écran externe ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Fermer"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micro et caméra"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applis"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consulter les accès récents"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 1b836a8..2056c2f 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Queres proxectar contido nunha pantalla externa?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Replicar pantalla"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Pechar"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono e cámara"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente por parte de aplicacións"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acceso recente"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 132ee2e..84be50a 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string>
     <string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"શું બાહ્ય ડિસ્પ્લે પર મિરર કરીએ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"મિરર ડિસ્પ્લે"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"છોડી દો"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"માઇક્રોફોન અને કૅમેરા"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"તાજેતરનો ઍપનો વપરાશ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"તાજેતરનો ઍક્સેસ મેનેજ કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f942de5..2b0019f 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string>
     <string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाहरी डिसप्ले को अन्य डिवाइस पर दिखाना है?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"मिरर डिसप्ले"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"खारिज करें"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफ़ोन और कैमरा"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"हाल ही में इस्तेमाल करने वाला ऐप्लिकेशन"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हाल में ऐक्सेस करने वाले ऐप"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index f7c68e1..23899fc 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalacija"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li zrcaliti na vanjski zaslon?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Zrcaljenje zaslona"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavna upotreba aplikacije"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Pogledajte nedavni pristup"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c1b38d9..e5b17d9 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string>
     <string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tükrözi a kijelzőt a külső képernyőre?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Kijelző tükrözése"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Elvetés"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon és kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Legutóbbi alkalmazáshasználat"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Legutóbbi hozzáférés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 7139a1f..4a1c291 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string>
     <string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Հայելապատճենե՞լ արտաքին էկրանին"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Հայելապատճենել էկրանը"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Փակել"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Խոսափող և տեսախցիկ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Հավելվածի վերջին օգտագործումը"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Տեսնել վերջին օգտագործումը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 44aafde..18a7668 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string>
     <string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Cerminkan ke layar eksternal?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Cerminkan layar"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Tutup"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon &amp; Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Penggunaan aplikasi baru-baru ini"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Lihat akses terbaru"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 1fda572..70bed46 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string>
     <string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spegla yfir á ytri skjá?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Spegla skjá"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Hunsa"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Hljóðnemi og myndavél"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nýlega notað af forriti"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Sjá nýlegan aðgang"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ed8885f..baffdb9 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string>
     <string name="install_app" msgid="5066668100199613936">"Installa app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vuoi eseguire il mirroring al display esterno?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Esegui il mirroring del display"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Chiudi"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfono e fotocamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente da app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Vedi accesso recente"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 51f5452..968a982 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string>
     <string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"לשקף למסך חיצוני?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"תצוגת מראה"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"סגירה"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"מיקרופון ומצלמה"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"נעשה שימוש לאחרונה באפליקציות"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"צפייה בהרשאות הגישה האחרונות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index e77aed9..798d42a 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string>
     <string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"外部ディスプレイにミラーリングしますか?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ディスプレイをミラーリングする"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"閉じる"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"マイクとカメラ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"最近のアプリの使用状況"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"最近のアクセスを表示"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 8d7deec..f21a2a4 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string>
     <string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"აირეკლოს გარე ეკრანზე?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ეკრანის არეკვლა"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"დახურვა"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"მიკროფონი და კამერა"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"აპის ბოლოდროინდელი გამოყენება"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ბოლო წვდომის ნახვა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index fc4fe8a..746c02e 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string>
     <string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Сыртқы экран арқылы да көрсету керек пе?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Айна дисплей"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Қабылдамау"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон және камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Соңғы рет қолданбаның датчикті пайдалануы"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Соңғы рет пайдаланғандар"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 10c291d..9f3b991 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string>
     <string name="install_app" msgid="5066668100199613936">"ដំឡើង​កម្មវិធី"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"បញ្ចាំងទៅ​ឧបករណ៍បញ្ចាំង​ខាងក្រៅឬ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"បញ្ចាំងទៅផ្ទាំងអេក្រង់"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"ច្រានចោល"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"មីក្រូហ្វូន និងកាមេរ៉ា"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ការប្រើប្រាស់កម្មវិធីថ្មីៗនេះ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"មើលការចូលប្រើនាពេលថ្មីៗនេះ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7716980..79eef72 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
     <string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ಬಾಹ್ಯ ಡಿಸ್‌ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಬೇಕೆ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ಮಿರರ್ ಡಿಸ್‌ಪ್ಲೇ"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"ವಜಾಗೊಳಿಸಿ"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಕ್ಯಾಮರಾ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ ಬಳಕೆ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ನೋಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index c2fbf09..7985e4c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string>
     <string name="install_app" msgid="5066668100199613936">"앱 설치"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"외부 디스플레이로 미러링하시겠습니까?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"디스플레이 미러링"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"닫기"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"마이크 및 카메라"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"최근 앱 사용"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"최근 액세스 보기"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 8ab4cb7..ded1f75 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string>
     <string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Тышкы экранга чыгарасызбы?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Тышкы экран"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Жабуу"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон жана камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Жакында колдонмолордо иштетилген"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Акыркы пайдалануусун көрүү"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index a1585f2..1e61b8a 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string>
     <string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ສາຍໃສ່ຈໍສະແດງຜົນພາຍນອກບໍ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ຈໍສະແດງຜົນແບບສະທ້ອນ"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"ປິດໄວ້"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ໄມໂຄຣໂຟນ ແລະ ກ້ອງຖ່າຍຮູບ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ການໃຊ້ແອັບຫຼ້າສຸດ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ເບິ່ງສິດເຂົ້າເຖິງຫຼ້າສຸດ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index c5f649c..06c1369 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string>
     <string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Bendrinti ekrano vaizdą išoriniame ekrane?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Bendrinti ekrano vaizdą"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Atsisakyti"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofonas ir fotoaparatas"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Pastarasis programos naudojimas"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Žr. pastarąją prieigą"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index d493609..fdf3028 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string>
     <string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vai spoguļot ārējā displejā?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Spoguļot displeju"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Nerādīt"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofons un kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nesen izmantoja lietotnes"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Skatīt neseno piekļuvi"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 46193b3..80ef7bb 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се синхронизира на надворешниот екран?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Отфрли"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Неодамнешно користење на апликација"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Видете го скорешниот пристап"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index d631538..5b1c80f 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string>
     <string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ബാഹ്യ ഡിസ്‌പ്ലേയിലേക്ക് മിറർ ചെയ്യണോ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"മിറർ ഡിസ്‌പ്ലേ"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"മൈക്രോഫോണും ക്യാമറയും"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"അടുത്തിടെയുള്ള ആപ്പ് ഉപയോഗം"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"അടുത്തിടെയുള്ള ആക്‌സസ് കാണുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index b16b22a..3f65931 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string>
     <string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Гадны дэлгэцэд тусгал үүсгэх үү?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Дэлгэцийн тусгал үүсгэх"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Хаах"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон болон камер"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Аппын саяхны ашиглалт"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Саяхны хандалтыг харах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 16fac23..238aaca 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अ‍ॅप सेट करा"</string>
     <string name="install_app" msgid="5066668100199613936">"अ‍ॅप इंस्टॉल करा"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेवर मिरर करायचे आहे का?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर करा"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"डिसमिस करा"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"मायक्रोफोन आणि कॅमेरा"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"अलीकडील अ‍ॅप वापर"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"अलीकडील अ‍ॅक्सेस पहा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 7cafdcd..8c764f1 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string>
     <string name="install_app" msgid="5066668100199613936">"Pasang apl"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Paparkan pada paparan luaran?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Segerakkan paparan"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Ketepikan"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon &amp; Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Penggunaan apl terbaharu"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Lihat akses terbaharu"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 620124e..883b9e9 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string>
     <string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ပြင်ပဖန်သားပြင်သို့ စကရင်ပွားမလား။"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ဖန်သားပြင်ကို စကရင်ပွားရန်"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"ပယ်ရန်"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"မိုက်ခရိုဖုန်းနှင့် ကင်မရာ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"လတ်တလော အက်ပ်အသုံးပြုမှု"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"လတ်တလောအသုံးပြုမှုကို ကြည့်ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 722cc12..53a4c52 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer appen"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du speile til en ekstern skjerm?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Speil skjermen"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Lukk"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon og kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nylig appbruk"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se nylig tilgang"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 74e5c6f..3b31b3a 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string>
     <string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेमा मिरर गर्ने हो?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर गर्नुहोस्"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"खारेज गर्नुहोस्"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफोन तथा क्यामेरा"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"एपको हालसालैको प्रयोग"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हालसालै एक्सेस गर्ने एप हेर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 6d97a9f..664af5e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string>
     <string name="install_app" msgid="5066668100199613936">"App installeren"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spiegelen naar extern scherm?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Scherm spiegelen"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Sluiten"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfoon en camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app-gebruik"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Recente toegang bekijken"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index a6e14f9..db9e0c5 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string>
     <string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେକୁ ମିରର କରିବେ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ଡିସପ୍ଲେ ମିରର କରନ୍ତୁ"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"ଖାରଜ କରନ୍ତୁ"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ମାଇକ୍ରୋଫୋନ ଏବଂ କେମେରା"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ବର୍ତ୍ତମାନର ଆପ ବ୍ୟବହାର"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ବର୍ତ୍ତମାନର ଆକ୍ସେସ ଦେଖନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index faca7b1..591c5e7 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string>
     <string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ਕੀ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰਨਾ ਹੈ?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ਡਿਸਪਲੇ ਨੂੰ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰੋ"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"ਖਾਰਜ ਕਰੋ"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਕੈਮਰਾ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ਹਾਲ ਹੀ ਵਿੱਚ ਵਰਤੀ ਗਈ ਐਪ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ਹਾਲੀਆ ਪਹੁੰਚ ਦੇਖੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 3bb539a..1951221 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string>
     <string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Powielić na wyświetlaczu zewnętrznym?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Powielaj obraz"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Zamknij"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i aparat"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Aplikacje korzystające w ostatnim czasie"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobacz ostatni dostęp"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8f93b73..693a3a1 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Dispensar"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente do app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consultar acessos recentes"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 02ee098..c4f1f67 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para o ecrã externo?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Espelhar ecrã"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Ignorar"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmara"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilização recente da app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acesso recente"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8f93b73..693a3a1 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Dispensar"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente do app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consultar acessos recentes"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 14cdeac..a942332 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Oglindești pe ecranul extern?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Afișare în oglindă"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Închide"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfon și cameră"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilizare recentă în aplicații"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Vezi accesarea recentă"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c5379c2..68601d6 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string>
     <string name="install_app" msgid="5066668100199613936">"Установить приложение"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублировать на внешний дисплей?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Дублировать дисплей"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Закрыть"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Недавнее использование приложениями"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Посмотреть недавний доступ"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index d53f0eb..86cb3c3 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string>
     <string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"බාහිර සංදර්ශකයට දර්පණය කරන්න ද?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"සංදර්ශකය දර්පණය කරන්න"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"අස් කරන්න"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"මයික්‍රොෆෝනය සහ කැමරාව"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"මෑත යෙදුම් භාවිතය"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"මෑත ප්‍රවේශය බලන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 7fa0d07..56b9f75 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string>
     <string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Chcete zrkadliť na externú obrazovku?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Zrkadliť obrazovku"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Zavrieť"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofón a fotoaparát"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedávne využitie aplikácie"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobraziť nedávny prístup"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 87c18f4..b72f750 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string>
     <string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite zrcaliti v zunanji zaslon?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Zrcali zaslon"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Opusti"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon in fotoaparat"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavna uporaba v aplikacijah"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ogled nedavnih dostopov"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 3e1471a..92f6f9c 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string>
     <string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Të pasqyrohet në ekranin e jashtëm?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Pasqyro ekranin"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Hiq"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoni dhe kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Përdorimi i fundit i aplikacionit"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Shiko qasjen e fundit"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 07897d7..7c0d9be 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Желите ли да пресликате на спољњи екран?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Одбаци"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Недавно користила апликација"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Прикажи недавни приступ"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index aee168e..323ce11f 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string>
     <string name="install_app" msgid="5066668100199613936">"Installera appen"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vill du spegla till extern skärm?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Spegla skärm"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Ignorera"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon och kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Senaste appanvändning"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se senaste åtkomst"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index be3badd..304910a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string>
     <string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Ungependa kuonyesha kwenye skrini ya nje?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Akisi skrini"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Ondoa"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Maikrofoni na Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Matumizi ya programu hivi majuzi"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Angalia ufikiaji wa majuzi"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 785c4d5..3ac5e2e 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string>
     <string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"வெளிப்புறக் காட்சிக்கு மிரர் செய்யவா?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"டிஸ்பிளேயை மிரர் செய்"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"வேண்டாம்"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"மைக்ரோஃபோனும் கேமராவும்"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"சமீபத்திய ஆப்ஸ் பயன்பாடு"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"சமீபத்திய அணுகலைக் காட்டு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 96d77b7..0526f95 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్‌లలో ఆటోమేటిక్‌గా ఉండేలా ఒక నోట్స్ యాప్‌ను సెట్ చేసుకోండి"</string>
     <string name="install_app" msgid="5066668100199613936">"యాప్‌ను ఇన్‌స్టాల్ చేయండి"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"బాహ్య డిస్‌ప్లే‌ను మిర్రర్ చేయాలా?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"మిర్రర్ డిస్‌ప్లే"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"విస్మరించండి"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"మైక్రోఫోన్ &amp; కెమెరా"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ఇటీవలి యాప్ వినియోగం"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ఇటీవలి యాక్సెస్‌ను చూడండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index f8fbfbe..8949360 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string>
     <string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"มิเรอร์ไปยังจอแสดงผลภายนอกไหม"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"มิเรอร์จอแสดงผล"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"ปิด"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ไมโครโฟนและกล้อง"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"การใช้แอปครั้งล่าสุด"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ดูการเข้าถึงล่าสุด"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 435398d..e5c11df 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string>
     <string name="install_app" msgid="5066668100199613936">"I-install ang app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"I-mirror sa external na display?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"I-mirror ang display"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"I-dismiss"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikropono at Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Kamakailang paggamit ng app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Tingnan ang kamakailang access"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d0ddbec..3552d92 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string>
     <string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Harici ekrana yansıtılsın mı?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Ekranı yansıt"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Kapat"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon ve Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Son uygulama kullanımı"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Son erişimi göster"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 1489dc7..2e6aea9 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string>
     <string name="install_app" msgid="5066668100199613936">"Установити додаток"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублювати на зовнішньому екрані?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Дублювати екран"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Закрити"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Мікрофон і камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Нещодавнє використання додатками"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Переглянути нещодавній доступ"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 9d69a5e..2e2fc41 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string>
     <string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"بیرونی ڈسپلے پر مرر کریں؟"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"ڈسپلے کو دو طرفہ مطابقت پذیر بنائیں"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"برخاست کریں"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"مائیکروفون اور کیمرا"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"حالیہ ایپ کا استعمال"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"حالیہ رسائی دیکھیں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 31b216b..a8654d5 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standart qaydlar ilovasini Sozlamalar orqali tanlang"</string>
     <string name="install_app" msgid="5066668100199613936">"Ilovani oʻrnatish"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tashqi displeyda aks ettirilsinmi?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Displeyni akslantirish"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Yopish"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon va kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ilovadan oxirgi foydalanish"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Oxirgi ruxsatni koʻrish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 814e0a6..5443745 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string>
     <string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Đồng bộ hoá hai chiều sang màn hình ngoài?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Phản chiếu màn hình"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Đóng"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrô và máy ảnh"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Hoạt động sử dụng gần đây của ứng dụng"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Xem hoạt động truy cập gần đây"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 8b2caf0..44c163b 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string>
     <string name="install_app" msgid="5066668100199613936">"安装应用"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"镜像到外接显示屏?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"镜像显示"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"关闭"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"麦克风和摄像头"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"近期应用对手机传感器的使用情况"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期使用情况"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 8a160c3..f45b2fe 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string>
     <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要鏡像投射至外部顯示屏嗎?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"關閉"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"麥克風和相機"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"近期應用程式使用情況"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期存取記錄"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 38b81a0..5a5bb9d 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string>
     <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要以鏡像方式投放至外部螢幕嗎?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"關閉"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"麥克風和相機"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"最近曾使用感應器的應用程式"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期存取記錄"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index fc70417..8b6bfae 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1183,10 +1183,8 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string>
     <string name="install_app" msgid="5066668100199613936">"Faka i-app"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Fanisa nesibonisi sangaphandle?"</string>
-    <!-- no translation found for mirror_display (2515262008898122928) -->
-    <skip />
-    <!-- no translation found for dismiss_dialog (2195508495854675882) -->
-    <skip />
+    <string name="mirror_display" msgid="2515262008898122928">"Isibonisi sokufanisa"</string>
+    <string name="dismiss_dialog" msgid="2195508495854675882">"Chitha"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Imakrofoni Nekhamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ukusetshenziswa kwakamuva kwe-app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Bona ukufinyelela kwakamuva"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 18f24ec..1add90f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -354,9 +354,6 @@
     <!-- Whether to show activity indicators in the status bar -->
     <bool name="config_showActivity">false</bool>
 
-    <!-- Whether or not the button to clear all notifications will be shown. -->
-    <bool name="config_enableNotificationsClearAll">true</bool>
-
     <!-- Whether or not to show the notification shelf that houses the icons of notifications that
      have been scrolled off-screen. -->
     <bool name="config_showNotificationShelf">true</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0ee5da2..5a83c7d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -846,12 +846,17 @@
     <!-- Amount the button should shake when it's not long-pressed for long enough. -->
     <dimen name="keyguard_affordance_shake_amplitude">8dp</dimen>
 
-    <dimen name="keyguard_affordance_horizontal_offset">32dp</dimen>
+    <dimen name="keyguard_affordance_horizontal_offset">16dp</dimen>
     <dimen name="keyguard_affordance_vertical_offset">32dp</dimen>
     <!-- Value should be at least sum of 'keyguard_affordance_width' +
          'keyguard_affordance_horizontal_offset' -->
     <dimen name="keyguard_indication_area_padding">82dp</dimen>
 
+    <!-- The width/padding of the communal tutorial indicator on keyguard. -->
+    <dimen name="communal_tutorial_indicator_fixed_width">168dp</dimen>
+    <dimen name="communal_tutorial_indicator_padding">24dp</dimen>
+    <dimen name="communal_tutorial_indicator_horizontal_offset">32dp</dimen>
+
     <!-- The width/height of the unlock icon view on keyguard. -->
     <dimen name="keyguard_lock_height">42dp</dimen>
     <dimen name="keyguard_lock_padding">20dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 81101d8..85b9864 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -222,6 +222,7 @@
     <item type="id" name="lock_icon" />
     <item type="id" name="lock_icon_bg" />
     <item type="id" name="burn_in_layer" />
+    <item type="id" name="communal_tutorial_indicator" />
 
     <!-- Privacy dialog -->
     <item type="id" name="privacy_dialog_close_app_button" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a2637d5..321594f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1043,6 +1043,9 @@
     <!-- Indication on the keyguard that is shown when the device is dock charging. [CHAR LIMIT=80]-->
     <string name="keyguard_indication_charging_time_dock"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Charging • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
 
+    <!-- Indicator shown to start the communal tutorial. [CHAR LIMIT=100] -->
+    <string name="communal_tutorial_indicator_text">Click on the arrow button to start the communal tutorial</string>
+
     <!-- Related to user switcher --><skip/>
 
     <!-- Accessibility label for the button that opens the user switcher. -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
new file mode 100644
index 0000000..57a49c8
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 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.dagger.qualifiers
+
+import java.lang.annotation.Documented
+import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy.RUNTIME
+import javax.inject.Qualifier
+
+/** Annotates a class that is display specific. */
+@Qualifier @Documented @Retention(RUNTIME) annotation class DisplaySpecific
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
index 5d036fb..b44bf39 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
@@ -71,7 +71,6 @@
 
     private AnimatedVectorDrawable mAnimatedDrawable;
     private boolean mIsShowing;
-    private boolean mCanShow = true;
     private int mDisplayRotation;
 
     private boolean mIsTaskbarVisible = false;
@@ -150,7 +149,7 @@
 
     @Override
     public boolean show() {
-        if (!mCanShow || mIsShowing) {
+        if (mIsShowing) {
             return false;
         }
 
@@ -222,14 +221,6 @@
     }
 
     @Override
-    public void setCanShowRotationButton(boolean canShow) {
-        mCanShow = canShow;
-        if (!mCanShow) {
-            hide();
-        }
-    }
-
-    @Override
     public void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) {
         mIsTaskbarVisible = taskbarVisible;
         mIsTaskbarStashed = taskbarStashed;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java
index 89f71eb..42dda0a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java
@@ -36,7 +36,6 @@
     default boolean isVisible() {
         return false;
     }
-    default void setCanShowRotationButton(boolean canShow) {}
     default void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) {}
     default void updateIcon(int lightIconColor, int darkIconColor) { }
     default void setOnClickListener(View.OnClickListener onClickListener) { }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index c074988..1e89614 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -283,12 +283,28 @@
     }
 
     public void setRotationLockedAtAngle(int rotationSuggestion, String caller) {
-        RotationPolicy.setRotationLockAtAngle(mContext, /* enabled= */ isRotationLocked(),
+        final Boolean isLocked = isRotationLocked();
+        if (isLocked == null) {
+            // Ignore if we can't read the setting for the current user
+            return;
+        }
+        RotationPolicy.setRotationLockAtAngle(mContext, /* enabled= */ isLocked,
                 /* rotation= */ rotationSuggestion, caller);
     }
 
-    public boolean isRotationLocked() {
-        return RotationPolicy.isRotationLocked(mContext);
+    /**
+     * @return whether rotation is currently locked, or <code>null</code> if the setting couldn't
+     *         be read
+     */
+    public Boolean isRotationLocked() {
+        try {
+            return RotationPolicy.isRotationLocked(mContext);
+        } catch (SecurityException e) {
+            // TODO(b/279561841): RotationPolicy uses the current user to resolve the setting which
+            //                    may change before the rotation watcher can be unregistered
+            Log.e(TAG, "Failed to get isRotationLocked", e);
+            return null;
+        }
     }
 
     public void setRotateSuggestionButtonState(boolean visible) {
@@ -462,7 +478,11 @@
 
         // If the screen rotation changes while locked, potentially update lock to flow with
         // new screen rotation and hide any showing suggestions.
-        boolean rotationLocked = isRotationLocked();
+        Boolean rotationLocked = isRotationLocked();
+        if (rotationLocked == null) {
+            // Ignore if we can't read the setting for the current user
+            return;
+        }
         // The isVisible check makes the rotation button disappear when we are not locked
         // (e.g. for tabletop auto-rotate).
         if (rotationLocked || mRotationButton.isVisible()) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 0094820..a6e04ce 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -23,6 +23,7 @@
 import android.window.PictureInPictureSurfaceTransaction;
 import android.window.TaskSnapshot;
 
+import com.android.internal.os.IResultReceiver;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 public class RecentsAnimationControllerCompat {
@@ -89,11 +90,16 @@
      * @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous
      *                          app.
      */
-    public void finish(boolean toHome, boolean sendUserLeaveHint) {
+    public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) {
         try {
-            mAnimationController.finish(toHome, sendUserLeaveHint);
+            mAnimationController.finish(toHome, sendUserLeaveHint, finishCb);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to finish recents animation", e);
+            try {
+                finishCb.send(0, null);
+            } catch (Exception ex) {
+                // Local call, can ignore
+            }
         }
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
index 1e7222d..88b9c02 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
@@ -233,6 +233,11 @@
                 runner.onAnimationCancelled();
                 finishRunnable.run();
             }
+
+            @Override
+            public void onTransitionConsumed(IBinder iBinder, boolean aborted)
+                    throws RemoteException {
+            }
         };
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 2f3c1f2..01a75d9 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.customization.R
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.DisplaySpecific
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags.DOZING_MIGRATION_1
@@ -79,7 +80,7 @@
     private val batteryController: BatteryController,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val configurationController: ConfigurationController,
-    @Main private val resources: Resources,
+    @DisplaySpecific private val resources: Resources,
     private val context: Context,
     @Main private val mainExecutor: DelayableExecutor,
     @Background private val bgExecutor: Executor,
@@ -205,19 +206,19 @@
     private var isRegistered = false
     private var disposableHandle: DisposableHandle? = null
     private val regionSamplingEnabled = featureFlags.isEnabled(REGION_SAMPLING)
-
+    private var largeClockOnSecondaryDisplay = false
 
     private fun updateColors() {
         if (regionSamplingEnabled) {
             clock?.let { clock ->
                 smallRegionSampler?.let {
-                    smallClockIsDark = it.currentRegionDarkness().isDark
-                    clock.smallClock.events.onRegionDarknessChanged(smallClockIsDark)
+                    val isRegionDark = it.currentRegionDarkness().isDark
+                    clock.smallClock.events.onRegionDarknessChanged(isRegionDark)
                 }
 
                 largeRegionSampler?.let {
-                    largeClockIsDark = it.currentRegionDarkness().isDark
-                    clock.largeClock.events.onRegionDarknessChanged(largeClockIsDark)
+                    val isRegionDark = it.currentRegionDarkness().isDark
+                    clock.largeClock.events.onRegionDarknessChanged(isRegionDark)
                 }
             }
             return
@@ -225,12 +226,12 @@
 
         val isLightTheme = TypedValue()
         context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true)
-        smallClockIsDark = isLightTheme.data == 0
-        largeClockIsDark = isLightTheme.data == 0
+        val isRegionDark = isLightTheme.data == 0
 
         clock?.run {
-            smallClock.events.onRegionDarknessChanged(smallClockIsDark)
-            largeClock.events.onRegionDarknessChanged(largeClockIsDark)
+            Log.i(TAG, "Region isDark: $isRegionDark")
+            smallClock.events.onRegionDarknessChanged(isRegionDark)
+            largeClock.events.onRegionDarknessChanged(isRegionDark)
         }
     }
     protected open fun createRegionSampler(
@@ -260,9 +261,6 @@
         get() = isKeyguardVisible && dozeAmount < DOZE_TICKRATE_THRESHOLD
     private var cachedWeatherData: WeatherData? = null
 
-    private var smallClockIsDark = true
-    private var largeClockIsDark = true
-
     private val configListener =
         object : ConfigurationController.ConfigurationListener {
             override fun onThemeChanged() {
@@ -381,6 +379,19 @@
                 ?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
     }
 
+    /**
+     * Sets this clock as showing in a secondary display.
+     *
+     * Not that this is not necessarily needed, as we could get the displayId from [Context]
+     * directly and infere [largeClockOnSecondaryDisplay] from the id being different than the
+     * default display one. However, if we do so, current screenshot tests would not work, as they
+     * pass an activity context always from the default display.
+     */
+    fun setLargeClockOnSecondaryDisplay(onSecondaryDisplay: Boolean) {
+        largeClockOnSecondaryDisplay = onSecondaryDisplay
+        updateFontSizes()
+    }
+
     private fun updateTimeListeners() {
         smallTimeListener?.stop()
         largeTimeListener?.stop()
@@ -403,9 +414,15 @@
             smallClock.events.onFontSettingChanged(
                 resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat()
             )
-            largeClock.events.onFontSettingChanged(
-                resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
-            )
+            largeClock.events.onFontSettingChanged(getLargeClockSizePx())
+        }
+    }
+
+    private fun getLargeClockSizePx(): Float {
+        return if (largeClockOnSecondaryDisplay) {
+            resources.getDimensionPixelSize(R.dimen.presentation_clock_text_size).toFloat()
+        } else {
+            resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt
index d677a15..dec7d79 100644
--- a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt
@@ -68,10 +68,13 @@
 
         clock = requireViewById(R.id.clock)
         keyguardStatusViewController =
-            keyguardStatusViewComponentFactory.build(clock).keyguardStatusViewController.apply {
-                setDisplayedOnSecondaryDisplay()
-                init()
-            }
+            keyguardStatusViewComponentFactory
+                .build(clock, display)
+                .keyguardStatusViewController
+                .apply {
+                    setDisplayedOnSecondaryDisplay()
+                    init()
+                }
     }
 
     /** [ConnectedDisplayKeyguardPresentation] factory. */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index ff8e489..3c8301f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -84,7 +84,6 @@
     private final DumpManager mDumpManager;
     private final ClockEventController mClockEventController;
     private final LogBuffer mLogBuffer;
-
     private FrameLayout mSmallClockFrame; // top aligned clock
     private FrameLayout mLargeClockFrame; // centered clock
 
@@ -265,6 +264,7 @@
 
         if (mShownOnSecondaryDisplay) {
             mView.setLargeClockOnSecondaryDisplay(true);
+            mClockEventController.setLargeClockOnSecondaryDisplay(true);
             displayClock(LARGE, /* animate= */ false);
             hideSliceViewAndNotificationIconContainer();
             return;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 9c015fe..8a6f101 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -419,7 +419,7 @@
             mClock.post(mMoveTextRunnable);
 
             mKeyguardClockSwitchController = mKeyguardStatusViewComponentFactory
-                    .build(findViewById(R.id.clock))
+                    .build(findViewById(R.id.clock), getDisplay())
                     .getKeyguardClockSwitchController();
 
             mKeyguardClockSwitchController.setOnlyClock(true);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 51c0676..50be97e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -139,7 +139,7 @@
             case PROMPT_REASON_USER_REQUEST:
                 return R.string.kg_prompt_after_user_lockdown_password;
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
-                return R.string.kg_prompt_unattended_update_password;
+                return R.string.kg_prompt_reason_timeout_password;
             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
                 return R.string.kg_prompt_reason_timeout_password;
             case PROMPT_REASON_TRUSTAGENT_EXPIRED:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 714ba81..57151ae 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -321,7 +321,7 @@
                 resId = R.string.kg_prompt_after_user_lockdown_pattern;
                 break;
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
-                resId = R.string.kg_prompt_unattended_update_pattern;
+                resId = R.string.kg_prompt_reason_timeout_pattern;
                 break;
             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
                 resId = R.string.kg_prompt_reason_timeout_pattern;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 9d6d033..681aa70 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -123,7 +123,7 @@
             case PROMPT_REASON_USER_REQUEST:
                 return R.string.kg_prompt_after_user_lockdown_pin;
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
-                return R.string.kg_prompt_unattended_update_pin;
+                return R.string.kg_prompt_reason_timeout_pin;
             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
                 return R.string.kg_prompt_reason_timeout_pin;
             case PROMPT_REASON_TRUSTAGENT_EXPIRED:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index f9cc03ee..d848602 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -18,7 +18,6 @@
 
 import static java.util.Collections.emptySet;
 
-import android.animation.LayoutTransition;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.os.Build;
@@ -79,14 +78,6 @@
         mKeyguardSlice = findViewById(R.id.keyguard_slice_view);
 
         mMediaHostContainer = findViewById(R.id.status_view_media_container);
-        if (mMediaHostContainer != null) {
-            LayoutTransition mediaLayoutTransition = new LayoutTransition();
-            ((ViewGroup) mMediaHostContainer).setLayoutTransition(mediaLayoutTransition);
-            mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
-            mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-            mediaLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
-            mediaLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING);
-        }
 
         updateDark();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 67b7052..79642bd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -23,7 +23,6 @@
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.animation.Animator;
-import android.animation.LayoutTransition;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.content.res.Configuration;
@@ -50,14 +49,15 @@
 import com.android.keyguard.KeyguardClockSwitch.ClockSize;
 import com.android.keyguard.logging.KeyguardLogger;
 import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
+import com.android.systemui.animation.ViewHierarchyAnimator;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
-import com.android.systemui.power.shared.model.ScreenPowerState;
 import com.android.systemui.plugins.ClockController;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.power.shared.model.ScreenPowerState;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -175,27 +175,10 @@
                             return;
                         }
 
-                        final LayoutTransition mediaLayoutTransition =
-                                ((ViewGroup) mediaHostContainer).getLayoutTransition();
-                        if (mediaLayoutTransition == null) return;
-
-                        mediaLayoutTransition.enableTransitionType(LayoutTransition.CHANGING);
+                        ViewHierarchyAnimator.Companion.animateNextUpdate(mediaHostContainer,
+                                Interpolators.STANDARD, /* duration= */ 500L,
+                                /* animateChildren= */ false);
                     });
-
-            mediaHostContainer.addOnLayoutChangeListener(
-                    (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
-                        final LayoutTransition mediaLayoutTransition =
-                                ((ViewGroup) mediaHostContainer).getLayoutTransition();
-                        if (mediaLayoutTransition == null) return;
-                        if (!mediaLayoutTransition.isTransitionTypeEnabled(
-                                LayoutTransition.CHANGING)) {
-                            return;
-                        }
-                        // Note: when this is called, the LayoutTransition is already been set up.
-                        // Disables the LayoutTransition until it's explicitly enabled again.
-                        mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGING);
-                    }
-            );
         }
 
         mDumpManager.registerDumpable(getInstanceName(), this);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3f5ec7d..3bf1482 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -189,6 +189,8 @@
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.settings.SecureSettings;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import com.google.android.collect.Lists;
 
 import java.io.PrintWriter;
@@ -4430,6 +4432,7 @@
     }
 
     @SuppressLint("MissingPermission")
+    @NeverCompile
     @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("KeyguardUpdateMonitor state:");
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index 1d2d77f..40d0be1 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -18,6 +18,7 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
@@ -68,6 +69,7 @@
     private boolean mUseBackground = false;
     private float mDozeAmount = 0f;
 
+    @SuppressLint("ClickableViewAccessibility")
     public LockIconView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mSensorRect = new RectF();
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index a81069a..83da80f 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -25,9 +25,11 @@
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
 import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+import static com.android.systemui.flags.Flags.NEW_AOD_TRANSITION;
 import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -56,11 +58,11 @@
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 
 import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.biometrics.AuthRippleController;
 import com.android.systemui.biometrics.UdfpsController;
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -72,12 +74,16 @@
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
+import dagger.Lazy;
+
 import java.io.PrintWriter;
 import java.util.Objects;
 import java.util.function.Consumer;
@@ -99,6 +105,8 @@
     private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
             VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
 
+    private static final long FADE_OUT_DURATION_MS = 250L;
+
     private final long mLongPressTimeout;
     @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @NonNull private final KeyguardViewController mKeyguardViewController;
@@ -124,6 +132,8 @@
     @NonNull private final KeyguardTransitionInteractor mTransitionInteractor;
     @NonNull private final KeyguardInteractor mKeyguardInteractor;
     @NonNull private final View.AccessibilityDelegate mAccessibilityDelegate;
+    @NonNull private final Lazy<BouncerInteractor> mBouncerInteractor;
+    @NonNull private final SceneContainerFlags mSceneContainerFlags;
 
     // Tracks the velocity of a touch to help filter out the touches that move too fast.
     private VelocityTracker mVelocityTracker;
@@ -200,7 +210,9 @@
             @NonNull KeyguardInteractor keyguardInteractor,
             @NonNull FeatureFlags featureFlags,
             PrimaryBouncerInteractor primaryBouncerInteractor,
-            Context context
+            Context context,
+            Lazy<BouncerInteractor> bouncerInteractor,
+            SceneContainerFlags sceneContainerFlags
     ) {
         mStatusBarStateController = statusBarStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -229,6 +241,8 @@
         dumpManager.registerDumpable(TAG, this);
         mResources = resources;
         mContext = context;
+        mBouncerInteractor = bouncerInteractor;
+        mSceneContainerFlags = sceneContainerFlags;
 
         mAccessibilityDelegate = new View.AccessibilityDelegate() {
             private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityAuthenticateHint =
@@ -253,6 +267,7 @@
     }
 
     /** Sets the LockIconView to the controller and rebinds any that depend on it. */
+    @SuppressLint("ClickableViewAccessibility")
     public void setLockIconView(LockIconView lockIconView) {
         mView = lockIconView;
         mView.setImageDrawable(mIcon);
@@ -302,6 +317,8 @@
         if (lockIconView.isAttachedToWindow()) {
             registerCallbacks();
         }
+
+        lockIconView.setOnTouchListener((view, motionEvent) -> onTouchEvent(motionEvent));
     }
 
     private void registerCallbacks() {
@@ -388,6 +405,16 @@
             mView.updateIcon(ICON_LOCK, true);
             mView.setContentDescription(mLockedLabel);
             mView.setVisibility(View.VISIBLE);
+        } else if (mIsDozing && mFeatureFlags.isEnabled(NEW_AOD_TRANSITION)) {
+            mView.animate()
+                    .alpha(0f)
+                    .setDuration(FADE_OUT_DURATION_MS)
+                    .withEndAction(() -> {
+                        mView.clearIcon();
+                        mView.setVisibility(View.INVISIBLE);
+                        mView.setContentDescription(null);
+                    })
+                    .start();
         } else {
             mView.clearIcon();
             mView.setVisibility(View.INVISIBLE);
@@ -622,19 +649,18 @@
     };
 
     /**
-     * Handles the touch if it is within the lock icon view and {@link #isActionable()} is true.
+     * Handles the touch if {@link #isActionable()} is true.
      * Subsequently, will trigger {@link #onLongPress()} if a touch is continuously in the lock icon
      * area for {@link #mLongPressTimeout} ms.
      *
      * Touch speed debouncing mimics logic from the velocity tracker in {@link UdfpsController}.
      */
-    public boolean onTouchEvent(MotionEvent event, Runnable onGestureDetectedRunnable) {
-        if (!onInterceptTouchEvent(event)) {
+    private boolean onTouchEvent(MotionEvent event) {
+        if (!actionableDownEventStartedOnView(event)) {
             cancelTouches();
             return false;
         }
 
-        mOnGestureDetectedRunnable = onGestureDetectedRunnable;
         switch(event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
             case MotionEvent.ACTION_HOVER_ENTER:
@@ -666,10 +692,10 @@
                 mVelocityTracker.addMovement(event);
                 // Compute pointer velocity in pixels per second.
                 mVelocityTracker.computeCurrentVelocity(1000);
-                float velocity = UdfpsController.computePointerSpeed(mVelocityTracker,
+                float velocity = computePointerSpeed(mVelocityTracker,
                         mActivePointerId);
                 if (event.getClassification() != MotionEvent.CLASSIFICATION_DEEP_PRESS
-                        && UdfpsController.exceedsVelocityThreshold(velocity)) {
+                        && exceedsVelocityThreshold(velocity)) {
                     Log.v(TAG, "lock icon long-press rescheduled due to "
                             + "high pointer velocity=" + velocity);
                     mLongPressCancelRunnable.run();
@@ -688,11 +714,24 @@
     }
 
     /**
-     * Intercepts the touch if the onDown event and current event are within this lock icon view's
-     * bounds.
+     * Calculate the pointer speed given a velocity tracker and the pointer id.
+     * This assumes that the velocity tracker has already been passed all relevant motion events.
      */
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (!inLockIconArea(event) || !isActionable()) {
+    private static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
+        final float vx = tracker.getXVelocity(pointerId);
+        final float vy = tracker.getYVelocity(pointerId);
+        return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0));
+    }
+
+    /**
+     * Whether the velocity exceeds the acceptable UDFPS debouncing threshold.
+     */
+    private static boolean exceedsVelocityThreshold(float velocity) {
+        return velocity > 750f;
+    }
+
+    private boolean actionableDownEventStartedOnView(MotionEvent event) {
+        if (!isActionable()) {
             return false;
         }
 
@@ -703,7 +742,8 @@
         return mDownDetected;
     }
 
-    private void onLongPress() {
+    @VisibleForTesting
+    protected void onLongPress() {
         cancelTouches();
         if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) {
             Log.v(TAG, "lock icon long-press rejected by the falsing manager.");
@@ -716,14 +756,15 @@
             mAuthRippleController.showUnlockRipple(FINGERPRINT);
         }
         updateVisibility();
-        if (mOnGestureDetectedRunnable != null) {
-            mOnGestureDetectedRunnable.run();
-        }
 
         // play device entry haptic (consistent with UDFPS controller longpress)
         vibrateOnLongPress();
 
-        mKeyguardViewController.showPrimaryBouncer(/* scrim */ true);
+        if (mSceneContainerFlags.isEnabled()) {
+            mBouncerInteractor.get().showOrUnlockDevice(null);
+        } else {
+            mKeyguardViewController.showPrimaryBouncer(/* scrim */ true);
+        }
     }
 
 
@@ -738,12 +779,6 @@
         }
     }
 
-    private boolean inLockIconArea(MotionEvent event) {
-        mView.getHitRect(mSensorTouchLocation);
-        return mSensorTouchLocation.contains((int) event.getX(), (int) event.getY())
-                && mView.getVisibility() == View.VISIBLE;
-    }
-
     private boolean isActionable() {
         if (mIsBouncerShowing) {
             Log.v(TAG, "lock icon long-press ignored, bouncer already showing.");
@@ -821,6 +856,19 @@
         }
     };
 
+    /**
+     * Whether the lock icon will handle a touch while dozing.
+     */
+    public boolean willHandleTouchWhileDozing(MotionEvent event) {
+        // is in lock icon area
+        mView.getHitRect(mSensorTouchLocation);
+        final boolean inLockIconArea =
+                mSensorTouchLocation.contains((int) event.getX(), (int) event.getY())
+                        && mView.getVisibility() == View.VISIBLE;
+
+        return inLockIconArea && actionableDownEventStartedOnView(event);
+    }
+
     private final View.OnClickListener mA11yClickListener = v -> onLongPress();
 
     private final AccessibilityManager.AccessibilityStateChangeListener
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt
new file mode 100644
index 0000000..1f145d8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt
@@ -0,0 +1,42 @@
+package com.android.keyguard.dagger
+
+import android.content.Context
+import android.content.res.Resources
+import android.view.Display
+import com.android.systemui.dagger.qualifiers.DisplaySpecific
+import com.android.systemui.util.kotlin.getOrNull
+import dagger.BindsOptionalOf
+import dagger.Module
+import dagger.Provides
+import java.util.Optional
+
+/**
+ * Binds display specific context and resources.
+ *
+ * When a [Display] is available in the scope, binds a [DisplaySpecific] [Context] and [Resources].
+ * When not available, the default display context and resources are used.
+ */
+@Module
+abstract class KeyguardDisplayModule {
+
+    @BindsOptionalOf abstract fun optionalDisplay(): Display
+
+    companion object {
+        @Provides
+        @DisplaySpecific
+        fun getDisplayContext(context: Context, optionalDisplay: Optional<Display>): Context {
+            val display = optionalDisplay.getOrNull() ?: return context
+            return if (context.displayId == display.displayId) {
+                context
+            } else {
+                context.createDisplayContext(display)
+            }
+        }
+
+        @Provides
+        @DisplaySpecific
+        fun getDisplayResources(@DisplaySpecific context: Context): Resources {
+            return context.resources
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java
index d342377..f3014f1 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java
@@ -16,6 +16,8 @@
 
 package com.android.keyguard.dagger;
 
+import android.view.Display;
+
 import com.android.keyguard.KeyguardClockSwitchController;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardStatusViewController;
@@ -28,13 +30,17 @@
  *
  * TODO: unify this with {@link KeyguardStatusBarViewComponent}
  */
-@Subcomponent(modules = {KeyguardStatusViewModule.class})
+@Subcomponent(modules = {KeyguardStatusViewModule.class, KeyguardDisplayModule.class})
 @KeyguardStatusViewScope
 public interface KeyguardStatusViewComponent {
     /** Simple factory for {@link KeyguardStatusViewComponent}. */
     @Subcomponent.Factory
     interface Factory {
-        KeyguardStatusViewComponent build(@BindsInstance KeyguardStatusView presentation);
+        /** Creates {@link KeyguardStatusViewComponent} for a given display. */
+        KeyguardStatusViewComponent build(
+                @BindsInstance KeyguardStatusView presentation,
+                @BindsInstance Display display
+        );
     }
 
     /** Builds a {@link com.android.keyguard.KeyguardClockSwitchController}. */
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 2dfb370..fe19616 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -451,7 +451,7 @@
     }
 
     fun logSubInfo(subInfo: SubscriptionInfo?) {
-        logBuffer.log(TAG, VERBOSE, { str1 = "$subInfo" }, { "SubInfo:$str1" })
+        logBuffer.log(TAG, DEBUG, { str1 = "$subInfo" }, { "SubInfo:$str1" })
     }
 
     fun logTimeFormatChanged(newTimeFormat: String?) {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 0180384..1a34cc4 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -15,129 +15,60 @@
 package com.android.systemui;
 
 import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.INotificationManager;
-import android.app.IWallpaperManager;
-import android.hardware.SensorPrivacyManager;
-import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.ArrayMap;
-import android.util.DisplayMetrics;
-import android.view.IWindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.Preconditions;
-import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.animation.DialogLaunchAnimator;
-import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dock.DockManager;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentService;
-import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
-import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-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.qs.tiles.dialog.InternetDialogFactory;
 import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
-import com.android.systemui.shared.system.PackageManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.events.PrivacyDotViewController;
-import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
-import com.android.systemui.statusbar.phone.AutoHideController;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
-import com.android.systemui.statusbar.phone.ManagedProfileController;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
-import com.android.systemui.statusbar.policy.AccessibilityController;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.SensorPrivacyController;
-import com.android.systemui.statusbar.policy.SmartReplyConstants;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.statusbar.window.StatusBarWindowController;
-import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
 import com.android.systemui.tuner.TunerService;
-import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.leak.GarbageMonitor;
-import com.android.systemui.util.leak.LeakDetector;
-import com.android.systemui.util.leak.LeakReporter;
-import com.android.systemui.util.sensors.AsyncSensorManager;
 
-import java.util.concurrent.Executor;
+import dagger.Lazy;
+
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
-import dagger.Lazy;
-
 /**
  * Class to handle ugly dependencies throughout sysui until we determine the
  * long-term dependency injection solution.
@@ -155,10 +86,6 @@
  */
 @SysUISingleton
 public class Dependency {
-    /**
-     * Key for getting a the main looper.
-     */
-    private static final String MAIN_LOOPER_NAME = "main_looper";
 
     /**
      * Key for getting a background Looper for background work.
@@ -172,15 +99,6 @@
      * Generic handler on the main thread.
      */
     private static final String MAIN_HANDLER_NAME = "main_handler";
-    /**
-     * Generic executor on the main thread.
-     */
-    private static final String MAIN_EXECUTOR_NAME = "main_executor";
-
-    /**
-     * Generic executor on a background thread.
-     */
-    private static final String BACKGROUND_EXECUTOR_NAME = "background_executor";
 
     /**
      * An email address to send memory leak reports to by default.
@@ -198,10 +116,6 @@
      */
     public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>(BG_LOOPER_NAME);
     /**
-     * Key for getting a mainer Looper.
-     */
-    public static final DependencyKey<Looper> MAIN_LOOPER = new DependencyKey<>(MAIN_LOOPER_NAME);
-    /**
      * Key for getting a Handler for receiving time tick broadcasts on.
      */
     public static final DependencyKey<Handler> TIME_TICK_HANDLER =
@@ -212,134 +126,43 @@
     public static final DependencyKey<Handler> MAIN_HANDLER =
             new DependencyKey<>(MAIN_HANDLER_NAME);
 
-    /**
-     * Generic executor on the main thread.
-     */
-    public static final DependencyKey<Executor> MAIN_EXECUTOR =
-            new DependencyKey<>(MAIN_EXECUTOR_NAME);
-    /**
-     * Generic executor on a background thread.
-     */
-    public static final DependencyKey<Executor> BACKGROUND_EXECUTOR =
-            new DependencyKey<>(BACKGROUND_EXECUTOR_NAME);
-
-    /**
-     * An email address to send memory leak reports to by default.
-     */
-    public static final DependencyKey<String> LEAK_REPORT_EMAIL =
-            new DependencyKey<>(LEAK_REPORT_EMAIL_NAME);
-
     private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>();
     private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>();
 
     @Inject DumpManager mDumpManager;
 
-    @Inject Lazy<ActivityStarter> mActivityStarter;
     @Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher;
-    @Inject Lazy<AsyncSensorManager> mAsyncSensorManager;
     @Inject Lazy<BluetoothController> mBluetoothController;
-    @Inject Lazy<LocationController> mLocationController;
-    @Inject Lazy<RotationLockController> mRotationLockController;
-    @Inject Lazy<ZenModeController> mZenModeController;
-    @Inject Lazy<HotspotController> mHotspotController;
-    @Inject Lazy<CastController> mCastController;
     @Inject Lazy<FlashlightController> mFlashlightController;
-    @Inject Lazy<UserSwitcherController> mUserSwitcherController;
-    @Inject Lazy<UserInfoController> mUserInfoController;
-    @Inject Lazy<KeyguardStateController> mKeyguardMonitor;
     @Inject Lazy<KeyguardUpdateMonitor> mKeyguardUpdateMonitor;
-    @Inject Lazy<NightDisplayListener> mNightDisplayListener;
-    @Inject Lazy<ReduceBrightColorsController> mReduceBrightColorsController;
-    @Inject Lazy<ManagedProfileController> mManagedProfileController;
-    @Inject Lazy<NextAlarmController> mNextAlarmController;
-    @Inject Lazy<DataSaverController> mDataSaverController;
-    @Inject Lazy<AccessibilityController> mAccessibilityController;
     @Inject Lazy<DeviceProvisionedController> mDeviceProvisionedController;
     @Inject Lazy<PluginManager> mPluginManager;
     @Inject Lazy<AssistManager> mAssistManager;
-    @Inject Lazy<SecurityController> mSecurityController;
-    @Inject Lazy<LeakDetector> mLeakDetector;
-    @Inject Lazy<LeakReporter> mLeakReporter;
-    @Inject Lazy<GarbageMonitor> mGarbageMonitor;
     @Inject Lazy<TunerService> mTunerService;
-    @Inject Lazy<NotificationShadeWindowController> mNotificationShadeWindowController;
-    @Inject Lazy<StatusBarWindowController> mTempStatusBarWindowController;
     @Inject Lazy<DarkIconDispatcher> mDarkIconDispatcher;
-    @Inject Lazy<StatusBarIconController> mStatusBarIconController;
-    @Inject Lazy<ScreenLifecycle> mScreenLifecycle;
-    @Inject Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
     @Inject Lazy<FragmentService> mFragmentService;
-    @Inject Lazy<ExtensionController> mExtensionController;
-    @Inject Lazy<PluginDependencyProvider> mPluginDependencyProvider;
     @Nullable
-    @Inject Lazy<LocalBluetoothManager> mLocalBluetoothManager;
     @Inject Lazy<VolumeDialogController> mVolumeDialogController;
     @Inject Lazy<MetricsLogger> mMetricsLogger;
-    @Inject Lazy<AccessibilityManagerWrapper> mAccessibilityManagerWrapper;
-    @Inject Lazy<SysuiColorExtractor> mSysuiColorExtractor;
     @Inject Lazy<TunablePaddingService> mTunablePaddingService;
     @Inject Lazy<UiOffloadThread> mUiOffloadThread;
-    @Inject Lazy<PowerUI.WarningsUI> mWarningsUI;
     @Inject Lazy<LightBarController> mLightBarController;
-    @Inject Lazy<IWindowManager> mIWindowManager;
     @Inject Lazy<OverviewProxyService> mOverviewProxyService;
     @Inject Lazy<NavigationModeController> mNavBarModeController;
     @Inject Lazy<AccessibilityButtonModeObserver> mAccessibilityButtonModeObserver;
     @Inject Lazy<AccessibilityButtonTargetsObserver> mAccessibilityButtonListController;
-    @Inject Lazy<EnhancedEstimates> mEnhancedEstimates;
-    @Inject Lazy<VibratorHelper> mVibratorHelper;
     @Inject Lazy<IStatusBarService> mIStatusBarService;
-    @Inject Lazy<DisplayMetrics> mDisplayMetrics;
-    @Inject Lazy<LockscreenGestureLogger> mLockscreenGestureLogger;
-    @Inject Lazy<ShadeController> mShadeController;
     @Inject Lazy<NotificationRemoteInputManager.Callback> mNotificationRemoteInputManagerCallback;
-    @Inject Lazy<AppOpsController> mAppOpsController;
     @Inject Lazy<NavigationBarController> mNavigationBarController;
-    @Inject Lazy<AccessibilityFloatingMenuController> mAccessibilityFloatingMenuController;
     @Inject Lazy<StatusBarStateController> mStatusBarStateController;
-    @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager;
-    @Inject Lazy<NotificationGutsManager> mNotificationGutsManager;
     @Inject Lazy<NotificationMediaManager> mNotificationMediaManager;
-    @Inject Lazy<NotificationRemoteInputManager> mNotificationRemoteInputManager;
-    @Inject Lazy<SmartReplyConstants> mSmartReplyConstants;
-    @Inject Lazy<NotificationListener> mNotificationListener;
-    @Inject Lazy<NotificationLogger> mNotificationLogger;
-    @Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
-    @Inject Lazy<SmartReplyController> mSmartReplyController;
-    @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
-    @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
-    @Inject Lazy<AutoHideController> mAutoHideController;
-    @Inject Lazy<PrivacyItemController> mPrivacyItemController;
     @Inject @Background Lazy<Looper> mBgLooper;
-    @Inject @Background Lazy<Handler> mBgHandler;
-    @Inject @Main Lazy<Looper> mMainLooper;
     @Inject @Main Lazy<Handler> mMainHandler;
     @Inject @Named(TIME_TICK_HANDLER_NAME) Lazy<Handler> mTimeTickHandler;
-    @Inject @Named(LEAK_REPORT_EMAIL_NAME) Lazy<String> mLeakReportEmail;
-    @Inject @Main Lazy<Executor> mMainExecutor;
-    @Inject @Background Lazy<Executor> mBackgroundExecutor;
-    @Inject Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
-    @Inject Lazy<DevicePolicyManagerWrapper> mDevicePolicyManagerWrapper;
-    @Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper;
-    @Inject Lazy<SensorPrivacyController> mSensorPrivacyController;
-    @Inject Lazy<DockManager> mDockManager;
-    @Inject Lazy<INotificationManager> mINotificationManager;
     @Inject Lazy<SysUiState> mSysUiStateFlagsContainer;
-    @Inject Lazy<AlarmManager> mAlarmManager;
-    @Inject Lazy<KeyguardSecurityModel> mKeyguardSecurityModel;
-    @Inject Lazy<DozeParameters> mDozeParameters;
-    @Inject Lazy<IWallpaperManager> mWallpaperManager;
     @Inject Lazy<CommandQueue> mCommandQueue;
-    @Inject Lazy<RecordingController> mRecordingController;
-    @Inject Lazy<MediaOutputDialogFactory> mMediaOutputDialogFactory;
-    @Inject Lazy<DeviceConfigProxy> mDeviceConfigProxy;
-    @Inject Lazy<TelephonyListenerManager> mTelephonyListenerManager;
-    @Inject Lazy<SystemStatusAnimationScheduler> mSystemStatusAnimationSchedulerLazy;
-    @Inject Lazy<PrivacyDotViewController> mPrivacyDotViewControllerLazy;
-    @Inject Lazy<EdgeBackGestureHandler.Factory> mEdgeBackGestureHandlerFactoryLazy;
     @Inject Lazy<UiEventLogger> mUiEventLogger;
     @Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy;
-    @Inject Lazy<InternetDialogFactory> mInternetDialogFactory;
     @Inject Lazy<FeatureFlags> mFeatureFlagsLazy;
     @Inject Lazy<NotificationSectionsManager> mNotificationSectionsManagerLazy;
     @Inject Lazy<ScreenOffAnimationController> mScreenOffAnimationController;
@@ -362,184 +185,36 @@
         // on imports.
         mProviders.put(TIME_TICK_HANDLER, mTimeTickHandler::get);
         mProviders.put(BG_LOOPER, mBgLooper::get);
-        mProviders.put(MAIN_LOOPER, mMainLooper::get);
         mProviders.put(MAIN_HANDLER, mMainHandler::get);
-        mProviders.put(MAIN_EXECUTOR, mMainExecutor::get);
-        mProviders.put(BACKGROUND_EXECUTOR, mBackgroundExecutor::get);
-        mProviders.put(ActivityStarter.class, mActivityStarter::get);
         mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get);
-
-        mProviders.put(AsyncSensorManager.class, mAsyncSensorManager::get);
-
         mProviders.put(BluetoothController.class, mBluetoothController::get);
-        mProviders.put(SensorPrivacyManager.class, mSensorPrivacyManager::get);
-
-        mProviders.put(LocationController.class, mLocationController::get);
-
-        mProviders.put(RotationLockController.class, mRotationLockController::get);
-
-        mProviders.put(ZenModeController.class, mZenModeController::get);
-
-        mProviders.put(HotspotController.class, mHotspotController::get);
-
-        mProviders.put(CastController.class, mCastController::get);
-
         mProviders.put(FlashlightController.class, mFlashlightController::get);
-
-        mProviders.put(KeyguardStateController.class, mKeyguardMonitor::get);
-
         mProviders.put(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor::get);
-
-        mProviders.put(UserSwitcherController.class, mUserSwitcherController::get);
-
-        mProviders.put(UserInfoController.class, mUserInfoController::get);
-
-        mProviders.put(NightDisplayListener.class, mNightDisplayListener::get);
-
-        mProviders.put(ReduceBrightColorsController.class, mReduceBrightColorsController::get);
-
-        mProviders.put(ManagedProfileController.class, mManagedProfileController::get);
-
-        mProviders.put(NextAlarmController.class, mNextAlarmController::get);
-
-        mProviders.put(DataSaverController.class, mDataSaverController::get);
-
-        mProviders.put(AccessibilityController.class, mAccessibilityController::get);
-
         mProviders.put(DeviceProvisionedController.class, mDeviceProvisionedController::get);
-
         mProviders.put(PluginManager.class, mPluginManager::get);
-
         mProviders.put(AssistManager.class, mAssistManager::get);
-
-        mProviders.put(SecurityController.class, mSecurityController::get);
-
-        mProviders.put(LeakDetector.class, mLeakDetector::get);
-
-        mProviders.put(LEAK_REPORT_EMAIL, mLeakReportEmail::get);
-
-        mProviders.put(LeakReporter.class, mLeakReporter::get);
-
-        mProviders.put(GarbageMonitor.class, mGarbageMonitor::get);
-
         mProviders.put(TunerService.class, mTunerService::get);
-
-        mProviders.put(NotificationShadeWindowController.class,
-                mNotificationShadeWindowController::get);
-
-        mProviders.put(StatusBarWindowController.class, mTempStatusBarWindowController::get);
-
         mProviders.put(DarkIconDispatcher.class, mDarkIconDispatcher::get);
-
-        mProviders.put(StatusBarIconController.class, mStatusBarIconController::get);
-
-        mProviders.put(ScreenLifecycle.class, mScreenLifecycle::get);
-
-        mProviders.put(WakefulnessLifecycle.class, mWakefulnessLifecycle::get);
-
         mProviders.put(FragmentService.class, mFragmentService::get);
-
-        mProviders.put(ExtensionController.class, mExtensionController::get);
-
-        mProviders.put(PluginDependencyProvider.class, mPluginDependencyProvider::get);
-
-        mProviders.put(LocalBluetoothManager.class, mLocalBluetoothManager::get);
-
         mProviders.put(VolumeDialogController.class, mVolumeDialogController::get);
-
         mProviders.put(MetricsLogger.class, mMetricsLogger::get);
-
-        mProviders.put(AccessibilityManagerWrapper.class, mAccessibilityManagerWrapper::get);
-
-        mProviders.put(SysuiColorExtractor.class, mSysuiColorExtractor::get);
-
         mProviders.put(TunablePaddingService.class, mTunablePaddingService::get);
-
         mProviders.put(UiOffloadThread.class, mUiOffloadThread::get);
-
-        mProviders.put(PowerUI.WarningsUI.class, mWarningsUI::get);
-
         mProviders.put(LightBarController.class, mLightBarController::get);
-
-        mProviders.put(IWindowManager.class, mIWindowManager::get);
-
         mProviders.put(OverviewProxyService.class, mOverviewProxyService::get);
-
         mProviders.put(NavigationModeController.class, mNavBarModeController::get);
-
         mProviders.put(AccessibilityButtonModeObserver.class,
                 mAccessibilityButtonModeObserver::get);
         mProviders.put(AccessibilityButtonTargetsObserver.class,
                 mAccessibilityButtonListController::get);
-
-        mProviders.put(EnhancedEstimates.class, mEnhancedEstimates::get);
-
-        mProviders.put(VibratorHelper.class, mVibratorHelper::get);
-
         mProviders.put(IStatusBarService.class, mIStatusBarService::get);
-
-        mProviders.put(DisplayMetrics.class, mDisplayMetrics::get);
-
-        mProviders.put(LockscreenGestureLogger.class, mLockscreenGestureLogger::get);
-
-        mProviders.put(ShadeController.class, mShadeController::get);
-
         mProviders.put(NotificationRemoteInputManager.Callback.class,
                 mNotificationRemoteInputManagerCallback::get);
-
-        mProviders.put(AppOpsController.class, mAppOpsController::get);
-
         mProviders.put(NavigationBarController.class, mNavigationBarController::get);
-
-        mProviders.put(AccessibilityFloatingMenuController.class,
-                mAccessibilityFloatingMenuController::get);
-
         mProviders.put(StatusBarStateController.class, mStatusBarStateController::get);
-        mProviders.put(NotificationLockscreenUserManager.class,
-                mNotificationLockscreenUserManager::get);
         mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get);
-        mProviders.put(NotificationGutsManager.class, mNotificationGutsManager::get);
-        mProviders.put(NotificationRemoteInputManager.class,
-                mNotificationRemoteInputManager::get);
-        mProviders.put(SmartReplyConstants.class, mSmartReplyConstants::get);
-        mProviders.put(NotificationListener.class, mNotificationListener::get);
-        mProviders.put(NotificationLogger.class, mNotificationLogger::get);
-        mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get);
-        mProviders.put(SmartReplyController.class, mSmartReplyController::get);
-        mProviders.put(RemoteInputQuickSettingsDisabler.class,
-                mRemoteInputQuickSettingsDisabler::get);
-        mProviders.put(PrivacyItemController.class, mPrivacyItemController::get);
-        mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get);
-        mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get);
-        mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get);
-        mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get);
-        mProviders.put(DockManager.class, mDockManager::get);
-        mProviders.put(INotificationManager.class, mINotificationManager::get);
         mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get);
-        mProviders.put(AlarmManager.class, mAlarmManager::get);
-        mProviders.put(KeyguardSecurityModel.class, mKeyguardSecurityModel::get);
-        mProviders.put(DozeParameters.class, mDozeParameters::get);
-        mProviders.put(IWallpaperManager.class, mWallpaperManager::get);
         mProviders.put(CommandQueue.class, mCommandQueue::get);
-        mProviders.put(DeviceConfigProxy.class, mDeviceConfigProxy::get);
-        mProviders.put(TelephonyListenerManager.class, mTelephonyListenerManager::get);
-
-        // TODO(b/118592525): to support multi-display , we start to add something which is
-        //                    per-display, while others may be global. I think it's time to add
-        //                    a new class maybe named DisplayDependency to solve per-display
-        //                    Dependency problem.
-        mProviders.put(AutoHideController.class, mAutoHideController::get);
-
-        mProviders.put(RecordingController.class, mRecordingController::get);
-
-        mProviders.put(MediaOutputDialogFactory.class, mMediaOutputDialogFactory::get);
-
-        mProviders.put(SystemStatusAnimationScheduler.class,
-                mSystemStatusAnimationSchedulerLazy::get);
-        mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get);
-        mProviders.put(InternetDialogFactory.class, mInternetDialogFactory::get);
-        mProviders.put(EdgeBackGestureHandler.Factory.class,
-                mEdgeBackGestureHandlerFactoryLazy::get);
         mProviders.put(UiEventLogger.class, mUiEventLogger::get);
         mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get);
         mProviders.put(StatusBarContentInsetsProvider.class, mContentInsetsProviderLazy::get);
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 4541384..b573fad 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -28,6 +28,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.qs.QSUserSwitcherEvent;
 import com.android.systemui.settings.UserTracker;
@@ -46,6 +47,7 @@
 /**
  * Manages notification when a guest session is resumed.
  */
+@SysUISingleton
 public class GuestResumeSessionReceiver {
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 4af2c74..6faee8c 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -83,7 +83,7 @@
 import com.android.systemui.decor.RoundedCornerResDelegateImpl;
 import com.android.systemui.decor.ScreenDecorCommand;
 import com.android.systemui.log.ScreenDecorationsLogger;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
@@ -93,6 +93,8 @@
 import com.android.systemui.util.concurrency.ThreadFactory;
 import com.android.systemui.util.settings.SecureSettings;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import kotlin.Pair;
 
 import java.io.PrintWriter;
@@ -163,7 +165,7 @@
     ScreenDecorHwcLayer mScreenDecorHwcLayer;
     private WindowManager mWindowManager;
     private int mRotation;
-    private SettingObserver mColorInversionSetting;
+    private UserSettingObserver mColorInversionSetting;
     @Nullable
     private DelayableExecutor mExecutor;
     private Handler mHandler;
@@ -684,7 +686,7 @@
 
             // Watch color inversion and invert the overlay as needed.
             if (mColorInversionSetting == null) {
-                mColorInversionSetting = new SettingObserver(mSecureSettings, mHandler,
+                mColorInversionSetting = new UserSettingObserver(mSecureSettings, mHandler,
                         Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
                         mUserTracker.getUserId()) {
                     @Override
@@ -1088,6 +1090,7 @@
         }
     }
 
+    @NeverCompile
     @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("ScreenDecorations state:");
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index 1ee06cc..56273eb 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -35,18 +35,19 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
 import com.android.systemui.assist.AssistLogger;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.assist.AssistantSessionEvent;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.navigationbar.NavigationBarController;
+import com.android.systemui.res.R;
+
+import dagger.Lazy;
 
 import java.util.Locale;
 
 import javax.inject.Inject;
 
-import dagger.Lazy;
-
 /**
  * Default UiController implementation. Shows white edge lights along the bottom of the phone,
  * expanding from the corners to meet in the center.
@@ -80,7 +81,8 @@
     @Inject
     public DefaultUiController(Context context, AssistLogger assistLogger,
             WindowManager windowManager, MetricsLogger metricsLogger,
-            Lazy<AssistManager> assistManagerLazy) {
+            Lazy<AssistManager> assistManagerLazy,
+            NavigationBarController navigationBarController) {
         mAssistLogger = assistLogger;
         mRoot = new FrameLayout(context);
         mWindowManager = windowManager;
@@ -103,6 +105,7 @@
 
         mInvocationLightsView = (InvocationLightsView)
                 LayoutInflater.from(context).inflate(R.layout.invocation_lights, mRoot, false);
+        mInvocationLightsView.setNavigationBarController(navigationBarController);
         mRoot.addView(mInvocationLightsView);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
index 4d89231..0cdb376 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
@@ -31,11 +31,10 @@
 import android.view.View;
 
 import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
-import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationBar;
+import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationBarTransitions;
+import com.android.systemui.res.R;
 
 import java.util.ArrayList;
 
@@ -64,6 +63,8 @@
     private final int mLightColor;
     @ColorInt
     private final int mDarkColor;
+    @Nullable
+    private NavigationBarController mNavigationBarController;
 
     // Allocate variable for screen location lookup to avoid memory alloc onDraw()
     private int[] mScreenLocation = new int[2];
@@ -279,12 +280,11 @@
 
     private void attemptRegisterNavBarListener() {
         if (!mRegistered) {
-            NavigationBarController controller = Dependency.get(NavigationBarController.class);
-            if (controller == null) {
+            if (mNavigationBarController == null) {
                 return;
             }
 
-            NavigationBar navBar = controller.getDefaultNavigationBar();
+            NavigationBar navBar = mNavigationBarController.getDefaultNavigationBar();
             if (navBar == null) {
                 return;
             }
@@ -296,12 +296,11 @@
 
     private void attemptUnregisterNavBarListener() {
         if (mRegistered) {
-            NavigationBarController controller = Dependency.get(NavigationBarController.class);
-            if (controller == null) {
+            if (mNavigationBarController == null) {
                 return;
             }
 
-            NavigationBar navBar = controller.getDefaultNavigationBar();
+            NavigationBar navBar = mNavigationBarController.getDefaultNavigationBar();
             if (navBar == null) {
                 return;
             }
@@ -310,4 +309,8 @@
             mRegistered = false;
         }
     }
+
+    public void setNavigationBarController(NavigationBarController navigationBarController) {
+        mNavigationBarController = navigationBarController;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt
deleted file mode 100644
index ca4b8ef..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics
-
-/**
- * Interface for controlling the on finger down & on finger up events.
- */
-interface AlternateUdfpsTouchProvider {
-
-    /**
-     * onPointerDown:
-     *
-     * This operation is used to notify the Fingerprint HAL that
-     * a fingerprint has been detected on the device's screen.
-     *
-     * See fingerprint/ISession#onPointerDown for more details.
-     */
-    fun onPointerDown(pointerId: Long, x: Int, y: Int, minor: Float, major: Float)
-
-    /**
-     * onPointerUp:
-     *
-     * This operation can be invoked when the HAL is performing any one of: ISession#authenticate,
-     * ISession#enroll, ISession#detectInteraction. This operation is used to indicate
-     * that a fingerprint that was previously down, is now up.
-     *
-     * See fingerprint/ISession#onPointerUp for more details.
-     */
-    fun onPointerUp(pointerId: Long)
-
-    /**
-     * onUiReady:
-     *
-     * This operation is used by the callee to notify the Fingerprint HAL that SystemUI is
-     * correctly configured for the fingerprint capture.
-     *
-     * See fingerprint/ISession#onUiReady for more details.
-     */
-    fun onUiReady()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index bdad413..395f68c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -37,9 +37,6 @@
     private float mDialogSuggestedAlpha = 1f;
     private float mNotificationShadeExpansion = 0f;
 
-    // Used for Udfps ellipse detection when flag is true, set by AnimationViewController
-    boolean mUseExpandedOverlay = false;
-
     // mAlpha takes into consideration the status bar expansion amount and dialog suggested alpha
     private int mAlpha;
     boolean mPauseAuth;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 79d9c1b..c9e4cbe 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -32,7 +32,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.biometrics.BiometricFingerprintConstants;
 import android.hardware.biometrics.SensorProperties;
@@ -54,7 +53,6 @@
 import android.view.HapticFeedbackConstants;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 
@@ -84,7 +82,6 @@
 import com.android.systemui.doze.DozeReceiver;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
 import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter;
@@ -102,7 +99,6 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.Execution;
-import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.util.time.SystemClock;
 
 import kotlin.Unit;
@@ -110,7 +106,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.Executor;
 
@@ -136,13 +131,8 @@
     private static final String TAG = "UdfpsController";
     private static final long AOD_SEND_FINGER_UP_DELAY_MILLIS = 1000;
 
-    // Minimum required delay between consecutive touch logs in milliseconds.
-    private static final long MIN_TOUCH_LOG_INTERVAL = 50;
     private static final long MIN_UNCHANGED_INTERACTION_LOG_INTERVAL = 50;
 
-    // This algorithm checks whether the touch is within the sensor's bounding box.
-    private static final int BOUNDING_BOX_TOUCH_CONFIG_ID = 0;
-
     private final Context mContext;
     private final Execution mExecution;
     private final FingerprintManager mFingerprintManager;
@@ -175,8 +165,6 @@
     @Nullable private final TouchProcessor mTouchProcessor;
     @NonNull private final SessionTracker mSessionTracker;
     @NonNull private final AlternateBouncerInteractor mAlternateBouncerInteractor;
-    @NonNull private final SecureSettings mSecureSettings;
-    @NonNull private final UdfpsUtils mUdfpsUtils;
     @NonNull private final InputManager mInputManager;
     @NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
     private final boolean mIgnoreRefreshRate;
@@ -187,11 +175,8 @@
     @VisibleForTesting @NonNull UdfpsOverlayParams mOverlayParams = new UdfpsOverlayParams();
     // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this.
     @Nullable private Runnable mAuthControllerUpdateUdfpsLocation;
-    @Nullable private final AlternateUdfpsTouchProvider mAlternateTouchProvider;
     @Nullable private UdfpsDisplayModeProvider mUdfpsDisplayMode;
 
-    // Tracks the velocity of a touch to help filter out the touches that move too fast.
-    @Nullable private VelocityTracker mVelocityTracker;
     // The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
     private int mActivePointerId = -1;
     // Whether a pointer has been pilfered for current gesture
@@ -259,8 +244,6 @@
         final int touchConfigId = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_selected_udfps_touch_detection);
         pw.println("mSensorProps=(" + mSensorProps + ")");
-        pw.println("Using new touch detection framework: " + mFeatureFlags.isEnabled(
-                Flags.UDFPS_NEW_TOUCH_DETECTION));
         pw.println("touchConfigId: " + touchConfigId);
     }
 
@@ -272,7 +255,6 @@
             mFgExecutor.execute(() -> UdfpsController.this.showUdfpsOverlay(
                     new UdfpsControllerOverlay(
                         mContext,
-                        mFingerprintManager,
                         mInflater,
                         mWindowManager,
                         mAccessibilityManager,
@@ -286,7 +268,6 @@
                         mKeyguardStateController,
                         mUnlockedScreenOffAnimationController,
                         mUdfpsDisplayMode,
-                        mSecureSettings,
                         requestId,
                         reason,
                         callback,
@@ -299,7 +280,6 @@
                         mFeatureFlags,
                         mPrimaryBouncerInteractor,
                         mAlternateBouncerInteractor,
-                        mUdfpsUtils,
                         mUdfpsKeyguardAccessibilityDelegate,
                         mUdfpsKeyguardViewModels
                     )));
@@ -376,13 +356,9 @@
          * Debug to run onUiReady
          */
         public void debugOnUiReady(int sensorId) {
-            if (UdfpsController.this.mAlternateTouchProvider != null) {
-                UdfpsController.this.mAlternateTouchProvider.onUiReady();
-            } else {
-                final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L;
-                UdfpsController.this.mFingerprintManager.onUdfpsUiEvent(
-                        FingerprintManager.UDFPS_UI_READY, requestId, sensorId);
-            }
+            final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L;
+            UdfpsController.this.mFingerprintManager.onUdfpsUiEvent(
+                    FingerprintManager.UDFPS_UI_READY, requestId, sensorId);
         }
     }
 
@@ -423,23 +399,6 @@
         mUdfpsDisplayMode = udfpsDisplayMode;
     }
 
-    /**
-     * Calculate the pointer speed given a velocity tracker and the pointer id.
-     * This assumes that the velocity tracker has already been passed all relevant motion events.
-     */
-    public static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
-        final float vx = tracker.getXVelocity(pointerId);
-        final float vy = tracker.getYVelocity(pointerId);
-        return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0));
-    }
-
-    /**
-     * Whether the velocity exceeds the acceptable UDFPS debouncing threshold.
-     */
-    public static boolean exceedsVelocityThreshold(float velocity) {
-        return velocity > 750f;
-    }
-
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -457,38 +416,6 @@
         }
     };
 
-    /**
-     * Forwards touches to the udfps controller / view
-     */
-    public boolean onTouch(MotionEvent event) {
-        if (mOverlay == null || mOverlay.isHiding()) {
-            return false;
-        }
-        // TODO(b/225068271): may not be correct but no way to get the id yet
-        return onTouch(mOverlay.getRequestId(), event, false);
-    }
-
-    /**
-     * @param x                   coordinate
-     * @param y                   coordinate
-     * @param relativeToUdfpsView true if the coordinates are relative to the udfps view; else,
-     *                            calculate from the display dimensions in portrait orientation
-     */
-    private boolean isWithinSensorArea(UdfpsView udfpsView, float x, float y,
-            boolean relativeToUdfpsView) {
-        if (relativeToUdfpsView) {
-            // TODO: move isWithinSensorArea to UdfpsController.
-            return udfpsView.isWithinSensorArea(x, y);
-        }
-
-        if (mOverlay == null || mOverlay.getAnimationViewController() == null) {
-            return false;
-        }
-
-        return !mOverlay.getAnimationViewController().shouldPauseAuth()
-                && mOverlayParams.getSensorBounds().contains((int) x, (int) y);
-    }
-
     private void tryDismissingKeyguard() {
         if (!mOnFingerDown) {
             playStartHaptic();
@@ -497,15 +424,6 @@
         mAttemptedToDismissKeyguard = true;
     }
 
-    @VisibleForTesting
-    boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
-        if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-            return newOnTouch(requestId, event, fromUdfpsView);
-        } else {
-            return oldOnTouch(requestId, event, fromUdfpsView);
-        }
-    }
-
     private int getBiometricSessionType() {
         if (mOverlay == null) {
             return -1;
@@ -566,7 +484,7 @@
         }
     }
 
-    private boolean newOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
+    private boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
         if (!fromUdfpsView) {
             Log.e(TAG, "ignoring the touch injected from outside of UdfpsView");
             return false;
@@ -580,7 +498,6 @@
                     + mOverlay.getRequestId());
             return false;
         }
-
         if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f
                 && !mAlternateBouncerInteractor.isVisibleState())
                 || mPrimaryBouncerInteractor.isInTransit()) {
@@ -654,8 +571,7 @@
                 break;
 
             case UNCHANGED:
-                if (!isWithinSensorArea(mOverlay.getOverlayView(), event.getRawX(), event.getRawY(),
-                        true) && mActivePointerId == MotionEvent.INVALID_POINTER_ID
+                if (mActivePointerId == MotionEvent.INVALID_POINTER_ID
                         && mAlternateBouncerInteractor.isVisibleState()) {
                     // No pointer on sensor, forward to keyguard if alternateBouncer is visible
                     mKeyguardViewManager.onTouch(event);
@@ -667,7 +583,7 @@
         logBiometricTouch(processedTouch.getEvent(), data);
 
         // Always pilfer pointers that are within sensor area or when alternate bouncer is showing
-        if (isWithinSensorArea(mOverlay.getOverlayView(), event.getRawX(), event.getRawY(), true)
+        if (mActivePointerId != MotionEvent.INVALID_POINTER_ID
                 || mAlternateBouncerInteractor.isVisibleState()) {
             shouldPilfer = true;
         }
@@ -680,146 +596,7 @@
             mPointerPilfered = true;
         }
 
-        return processedTouch.getTouchData().isWithinBounds(mOverlayParams.getNativeSensorBounds());
-    }
-
-    private boolean oldOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
-        if (mOverlay == null) {
-            Log.w(TAG, "ignoring onTouch with null overlay");
-            return false;
-        }
-        if (!mOverlay.matchesRequestId(requestId)) {
-            Log.w(TAG, "ignoring stale touch event: " + requestId + " current: "
-                    + mOverlay.getRequestId());
-            return false;
-        }
-
-        final UdfpsView udfpsView = mOverlay.getOverlayView();
-        boolean handled = false;
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-            case MotionEvent.ACTION_HOVER_ENTER:
-                Trace.beginSection("UdfpsController.onTouch.ACTION_DOWN");
-                // To simplify the lifecycle of the velocity tracker, make sure it's never null
-                // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
-                if (mVelocityTracker == null) {
-                    mVelocityTracker = VelocityTracker.obtain();
-                } else {
-                    // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
-                    // ACTION_DOWN, in that case we should just reuse the old instance.
-                    mVelocityTracker.clear();
-                }
-
-                final boolean withinSensorArea =
-                        isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView);
-                if (withinSensorArea) {
-                    Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0);
-                    Log.v(TAG, "onTouch | action down");
-                    // The pointer that causes ACTION_DOWN is always at index 0.
-                    // We need to persist its ID to track it during ACTION_MOVE that could include
-                    // data for many other pointers because of multi-touch support.
-                    mActivePointerId = event.getPointerId(0);
-                    mVelocityTracker.addMovement(event);
-                    handled = true;
-                    mAcquiredReceived = false;
-                }
-                if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) {
-                    Log.v(TAG, "onTouch | dismiss keyguard ACTION_DOWN");
-                    tryDismissingKeyguard();
-                }
-
-                Trace.endSection();
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-            case MotionEvent.ACTION_HOVER_MOVE:
-                Trace.beginSection("UdfpsController.onTouch.ACTION_MOVE");
-                final int idx = mActivePointerId == -1
-                        ? event.getPointerId(0)
-                        : event.findPointerIndex(mActivePointerId);
-                if (idx == event.getActionIndex()) {
-                    final boolean actionMoveWithinSensorArea =
-                            isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx),
-                                    fromUdfpsView);
-                    if ((fromUdfpsView || actionMoveWithinSensorArea)
-                            && shouldTryToDismissKeyguard()) {
-                        Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE");
-                        tryDismissingKeyguard();
-                        break;
-                    }
-                    // Map the touch to portrait mode if the device is in landscape mode.
-                    final Point scaledTouch = mUdfpsUtils.getTouchInNativeCoordinates(
-                            idx, event, mOverlayParams);
-                    if (actionMoveWithinSensorArea) {
-                        if (mVelocityTracker == null) {
-                            // touches could be injected, so the velocity tracker may not have
-                            // been initialized (via ACTION_DOWN).
-                            mVelocityTracker = VelocityTracker.obtain();
-                        }
-                        mVelocityTracker.addMovement(event);
-                        // Compute pointer velocity in pixels per second.
-                        mVelocityTracker.computeCurrentVelocity(1000);
-                        // Compute pointer speed from X and Y velocities.
-                        final float v = computePointerSpeed(mVelocityTracker, mActivePointerId);
-                        final float minor = event.getTouchMinor(idx);
-                        final float major = event.getTouchMajor(idx);
-                        final boolean exceedsVelocityThreshold = exceedsVelocityThreshold(v);
-                        final String touchInfo = String.format(
-                                "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b",
-                                minor, major, v, exceedsVelocityThreshold);
-                        final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
-
-                        if (!mOnFingerDown && !mAcquiredReceived && !exceedsVelocityThreshold) {
-                            final float scale = mOverlayParams.getScaleFactor();
-                            float scaledMinor = minor / scale;
-                            float scaledMajor = major / scale;
-                            onFingerDown(requestId, scaledTouch.x, scaledTouch.y, scaledMinor,
-                                    scaledMajor);
-
-                            Log.v(TAG, "onTouch | finger down: " + touchInfo);
-                            mTouchLogTime = mSystemClock.elapsedRealtime();
-                            handled = true;
-                        } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
-                            Log.v(TAG, "onTouch | finger move: " + touchInfo);
-                            mTouchLogTime = mSystemClock.elapsedRealtime();
-                        }
-                    } else {
-                        Log.v(TAG, "onTouch | finger outside");
-                        onFingerUp(requestId, udfpsView);
-                        // Maybe announce for accessibility.
-                        mFgExecutor.execute(() -> {
-                            if (mOverlay == null) {
-                                Log.e(TAG, "touch outside sensor area received"
-                                        + "but serverRequest is null");
-                                return;
-                            }
-                            mOverlay.onTouchOutsideOfSensorArea(scaledTouch);
-                        });
-                    }
-                }
-                Trace.endSection();
-                break;
-
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_HOVER_EXIT:
-                Trace.beginSection("UdfpsController.onTouch.ACTION_UP");
-                mActivePointerId = -1;
-                if (mVelocityTracker != null) {
-                    mVelocityTracker.recycle();
-                    mVelocityTracker = null;
-                }
-                Log.v(TAG, "onTouch | finger up");
-                mAttemptedToDismissKeyguard = false;
-                onFingerUp(requestId, udfpsView);
-                mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
-                Trace.endSection();
-                break;
-
-            default:
-                // Do nothing.
-        }
-        return handled;
+        return mActivePointerId != MotionEvent.INVALID_POINTER_ID;
     }
 
     private boolean shouldTryToDismissKeyguard() {
@@ -859,15 +636,12 @@
             @NonNull SystemUIDialogManager dialogManager,
             @NonNull LatencyTracker latencyTracker,
             @NonNull ActivityLaunchAnimator activityLaunchAnimator,
-            @NonNull Optional<Provider<AlternateUdfpsTouchProvider>> alternateTouchProvider,
             @NonNull @BiometricsBackground Executor biometricsExecutor,
             @NonNull PrimaryBouncerInteractor primaryBouncerInteractor,
             @NonNull SinglePointerTouchProcessor singlePointerTouchProcessor,
             @NonNull SessionTracker sessionTracker,
             @NonNull AlternateBouncerInteractor alternateBouncerInteractor,
-            @NonNull SecureSettings secureSettings,
             @NonNull InputManager inputManager,
-            @NonNull UdfpsUtils udfpsUtils,
             @NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
             @NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate,
             @NonNull Provider<UdfpsKeyguardViewModels> udfpsKeyguardViewModelsProvider) {
@@ -900,7 +674,6 @@
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
         mLatencyTracker = latencyTracker;
         mActivityLaunchAnimator = activityLaunchAnimator;
-        mAlternateTouchProvider = alternateTouchProvider.map(Provider::get).orElse(null);
         mSensorProps = new FingerprintSensorPropertiesInternal(
                 -1 /* sensorId */,
                 SensorProperties.STRENGTH_CONVENIENCE,
@@ -912,13 +685,10 @@
         mBiometricExecutor = biometricsExecutor;
         mPrimaryBouncerInteractor = primaryBouncerInteractor;
         mAlternateBouncerInteractor = alternateBouncerInteractor;
-        mSecureSettings = secureSettings;
-        mUdfpsUtils = udfpsUtils;
         mInputManager = inputManager;
         mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate;
 
-        mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
-                ? singlePointerTouchProcessor : null;
+        mTouchProcessor = singlePointerTouchProcessor;
         mSessionTracker = sessionTracker;
 
         mDumpManager.registerDumpable(TAG, this);
@@ -1172,16 +942,9 @@
     }
 
     private void dispatchOnUiReady(long requestId) {
-        if (mAlternateTouchProvider != null) {
-            mBiometricExecutor.execute(() -> {
-                mAlternateTouchProvider.onUiReady();
-                mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
-            });
-        } else {
-            mFingerprintManager.onUdfpsUiEvent(FingerprintManager.UDFPS_UI_READY, requestId,
-                    mSensorProps.sensorId);
-            mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
-        }
+        mFingerprintManager.onUdfpsUiEvent(FingerprintManager.UDFPS_UI_READY, requestId,
+                mSensorProps.sensorId);
+        mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
     }
 
     private void onFingerDown(
@@ -1241,24 +1004,8 @@
             }
         }
         mOnFingerDown = true;
-        if (mAlternateTouchProvider != null) {
-            mBiometricExecutor.execute(() -> {
-                mAlternateTouchProvider.onPointerDown(requestId, (int) x, (int) y, minor, major);
-            });
-            mFgExecutor.execute(() -> {
-                if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
-                    mKeyguardUpdateMonitor.onUdfpsPointerDown((int) requestId);
-                }
-            });
-        } else {
-            if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-                mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, pointerId, x, y,
-                        minor, major, orientation, time, gestureStart, isAod);
-            } else {
-                mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, (int) x,
-                        (int) y, minor, major);
-            }
-        }
+        mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, pointerId, x, y,
+                minor, major, orientation, time, gestureStart, isAod);
         Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
         final UdfpsView view = mOverlay.getOverlayView();
         if (view != null && isOptical()) {
@@ -1305,23 +1052,8 @@
         mActivePointerId = -1;
         mAcquiredReceived = false;
         if (mOnFingerDown) {
-            if (mAlternateTouchProvider != null) {
-                mBiometricExecutor.execute(() -> {
-                    mAlternateTouchProvider.onPointerUp(requestId);
-                });
-                mFgExecutor.execute(() -> {
-                    if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
-                        mKeyguardUpdateMonitor.onUdfpsPointerUp((int) requestId);
-                    }
-                });
-            } else {
-                if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-                    mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId, pointerId, x,
-                            y, minor, major, orientation, time, gestureStart, isAod);
-                } else {
-                    mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
-                }
-            }
+            mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId, pointerId, x,
+                    y, minor, major, orientation, time, gestureStart, isAod);
             for (Callback cb : mCallbacks) {
                 cb.onFingerUp();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 34a0d8a..7130bfb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -20,7 +20,6 @@
 import android.annotation.UiThread
 import android.content.Context
 import android.graphics.PixelFormat
-import android.graphics.Point
 import android.graphics.Rect
 import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
 import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
@@ -29,7 +28,6 @@
 import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
 import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
 import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
-import android.hardware.fingerprint.FingerprintManager
 import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
 import android.os.Build
 import android.os.RemoteException
@@ -54,7 +52,6 @@
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.flags.Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS
 import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter
 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels
@@ -65,7 +62,6 @@
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.settings.SecureSettings
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import javax.inject.Provider
 
@@ -83,7 +79,6 @@
 @UiThread
 class UdfpsControllerOverlay @JvmOverloads constructor(
         private val context: Context,
-        fingerprintManager: FingerprintManager,
         private val inflater: LayoutInflater,
         private val windowManager: WindowManager,
         private val accessibilityManager: AccessibilityManager,
@@ -97,7 +92,6 @@
         private val keyguardStateController: KeyguardStateController,
         private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
         private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
-        private val secureSettings: SecureSettings,
         val requestId: Long,
         @ShowReason val requestReason: Int,
         private val controllerCallback: IUdfpsOverlayControllerCallback,
@@ -107,7 +101,6 @@
         private val primaryBouncerInteractor: PrimaryBouncerInteractor,
         private val alternateBouncerInteractor: AlternateBouncerInteractor,
         private val isDebuggable: Boolean = Build.IS_DEBUGGABLE,
-        private val udfpsUtils: UdfpsUtils,
         private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
         private val udfpsKeyguardViewModels: Provider<UdfpsKeyguardViewModels>,
 ) {
@@ -134,10 +127,7 @@
         privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
         // Avoid announcing window title.
         accessibilityTitle = " "
-
-        if (featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-            inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY
-        }
+        inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY
     }
 
     /** If the overlay is currently showing. */
@@ -206,7 +196,6 @@
                         overlayTouchListener!!
                     )
                     overlayTouchListener?.onTouchExplorationStateChanged(true)
-                    useExpandedOverlay = featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
                 }
             } catch (e: RuntimeException) {
                 Log.e(TAG, "showUdfpsOverlay | failed to add window", e)
@@ -331,25 +320,6 @@
         return wasShowing
     }
 
-    /**
-     * This function computes the angle of touch relative to the sensor and maps
-     * the angle to a list of help messages which are announced if accessibility is enabled.
-     *
-     */
-    fun onTouchOutsideOfSensorArea(scaledTouch: Point) {
-        val theStr =
-            udfpsUtils.onTouchOutsideOfSensorArea(
-                touchExplorationEnabled,
-                context,
-                scaledTouch.x,
-                scaledTouch.y,
-                overlayParams
-            )
-        if (theStr != null) {
-            animationViewController?.doAnnounceForAccessibility(theStr)
-        }
-    }
-
     /** Cancel this request. */
     fun cancel() {
         try {
@@ -367,10 +337,6 @@
     ): WindowManager.LayoutParams {
         val paddingX = animation?.paddingX ?: 0
         val paddingY = animation?.paddingY ?: 0
-        if (!featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION) && animation != null &&
-                animation.listenForTouchesOutsideView()) {
-            flags = flags or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-        }
 
         val isEnrollment = when (requestReason) {
             REASON_ENROLL_FIND_SENSOR, REASON_ENROLL_ENROLLING -> true
@@ -379,19 +345,15 @@
 
         // Use expanded overlay unless touchExploration enabled
         var rotatedBounds =
-            if (featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-                if (accessibilityManager.isTouchExplorationEnabled && isEnrollment) {
-                    Rect(overlayParams.sensorBounds)
-                } else {
-                    Rect(
-                        0,
-                        0,
-                        overlayParams.naturalDisplayWidth,
-                        overlayParams.naturalDisplayHeight
-                    )
-                }
-            } else {
+            if (accessibilityManager.isTouchExplorationEnabled && isEnrollment) {
                 Rect(overlayParams.sensorBounds)
+            } else {
+                Rect(
+                    0,
+                    0,
+                    overlayParams.naturalDisplayWidth,
+                    overlayParams.naturalDisplayHeight
+                )
             }
 
         val rot = overlayParams.rotation
@@ -399,9 +361,9 @@
             if (!shouldRotate(animation)) {
                 Log.v(
                     TAG, "Skip rotating UDFPS bounds " + Surface.rotationToString(rot) +
-                            " animation=$animation" +
-                            " isGoingToSleep=${keyguardUpdateMonitor.isGoingToSleep}" +
-                            " isOccluded=${keyguardStateController.isOccluded}"
+                        " animation=$animation" +
+                        " isGoingToSleep=${keyguardUpdateMonitor.isGoingToSleep}" +
+                        " isOccluded=${keyguardStateController.isOccluded}"
                 )
             } else {
                 Log.v(TAG, "Rotate UDFPS bounds " + Surface.rotationToString(rot))
@@ -412,14 +374,12 @@
                     rot
                 )
 
-                if (featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-                    RotationUtils.rotateBounds(
-                            sensorBounds,
-                            overlayParams.naturalDisplayWidth,
-                            overlayParams.naturalDisplayHeight,
-                            rot
-                    )
-                }
+                RotationUtils.rotateBounds(
+                    sensorBounds,
+                    overlayParams.naturalDisplayWidth,
+                    overlayParams.naturalDisplayHeight,
+                    rot
+                )
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.kt
index 8cc15da..afe37d4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.kt
@@ -43,10 +43,6 @@
         return fingerprintDrawablePlaceHolder
     }
 
-    fun useExpandedOverlay(useExpandedOverlay: Boolean) {
-        mUseExpandedOverlay = useExpandedOverlay
-    }
-
     fun isVisible(): Boolean {
         return visible
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
index 8ce98a9..3d5be6f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
@@ -19,7 +19,6 @@
 import android.animation.ValueAnimator
 import android.content.res.Configuration
 import android.util.MathUtils
-import android.view.MotionEvent
 import android.view.View
 import androidx.annotation.VisibleForTesting
 import androidx.lifecycle.Lifecycle
@@ -27,16 +26,15 @@
 import com.android.app.animation.Interpolators
 import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.res.R
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
@@ -80,8 +78,6 @@
     ),
     UdfpsKeyguardViewControllerAdapter {
     private val uniqueIdentifier = this.toString()
-    private val useExpandedOverlay: Boolean =
-        featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
     private var showingUdfpsBouncer = false
     private var udfpsRequested = false
     private var qsExpansion = 0f
@@ -192,24 +188,6 @@
                 updateAlpha()
                 updatePauseAuth()
             }
-
-            /**
-             * Forward touches to the UdfpsController. This allows the touch to start from outside
-             * the sensor area and then slide their finger into the sensor area.
-             */
-            override fun onTouch(event: MotionEvent) {
-                // Don't forward touches if the shade has already started expanding.
-                if (transitionToFullShadeProgress != 0f) {
-                    return
-                }
-
-                // Forwarding touches not needed with expanded overlay
-                if (useExpandedOverlay) {
-                    return
-                } else {
-                    udfpsController.onTouch(event)
-                }
-            }
         }
 
     private val occludingAppBiometricUI: OccludingAppBiometricUI =
@@ -294,7 +272,6 @@
         keyguardViewManager.setOccludingAppBiometricUI(occludingAppBiometricUI)
         lockScreenShadeTransitionController.mUdfpsKeyguardViewControllerLegacy = this
         activityLaunchAnimator.addListener(activityLaunchAnimatorListener)
-        view.mUseExpandedOverlay = useExpandedOverlay
         view.startIconAsyncInflate {
             val animationViewInternal: View =
                 view.requireViewById(R.id.udfps_animation_view_internal)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java
index 36a42f9..95e3a76 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java
@@ -298,45 +298,34 @@
         pw.println("    mUdfpsRequested=" + mUdfpsRequested);
         pw.println("    mInterpolatedDarkAmount=" + mInterpolatedDarkAmount);
         pw.println("    mAnimationType=" + mAnimationType);
-        pw.println("    mUseExpandedOverlay=" + mUseExpandedOverlay);
     }
 
     private final AsyncLayoutInflater.OnInflateFinishedListener mLayoutInflaterFinishListener =
             new AsyncLayoutInflater.OnInflateFinishedListener() {
-        @Override
-        public void onInflateFinished(View view, int resid, ViewGroup parent) {
-            mFullyInflated = true;
-            mAodFp = view.findViewById(R.id.udfps_aod_fp);
-            mLockScreenFp = view.findViewById(R.id.udfps_lockscreen_fp);
-            mBgProtection = view.findViewById(R.id.udfps_keyguard_fp_bg);
+                @Override
+                public void onInflateFinished(View view, int resid, ViewGroup parent) {
+                    mFullyInflated = true;
+                    mAodFp = view.findViewById(R.id.udfps_aod_fp);
+                    mLockScreenFp = view.findViewById(R.id.udfps_lockscreen_fp);
+                    mBgProtection = view.findViewById(R.id.udfps_keyguard_fp_bg);
 
-            updatePadding();
-            updateColor();
-            updateAlpha();
+                    updatePadding();
+                    updateColor();
+                    updateAlpha();
 
-            if (mUseExpandedOverlay) {
-                final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-                lp.width = mSensorBounds.width();
-                lp.height = mSensorBounds.height();
-                RectF relativeToView = getBoundsRelativeToView(new RectF(mSensorBounds));
-                lp.setMarginsRelative(
-                        (int) relativeToView.left,
-                        (int) relativeToView.top,
-                        (int) relativeToView.right,
-                        (int) relativeToView.bottom
-                );
-                parent.addView(view, lp);
-            } else {
-                parent.addView(view);
-            }
+                    final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                    lp.width = mSensorBounds.width();
+                    lp.height = mSensorBounds.height();
+                    RectF relativeToView = getBoundsRelativeToView(new RectF(mSensorBounds));
+                    lp.setMarginsRelative((int) relativeToView.left, (int) relativeToView.top,
+                            (int) relativeToView.right, (int) relativeToView.bottom);
+                    parent.addView(view, lp);
 
-            // requires call to invalidate to update the color
-            mLockScreenFp.addValueCallback(
-                    new KeyPath("**"), LottieProperty.COLOR_FILTER,
-                    frameInfo -> new PorterDuffColorFilter(mTextColorPrimary,
-                            PorterDuff.Mode.SRC_ATOP)
-            );
-            mOnFinishInflateRunnable.run();
-        }
-    };
+                    // requires call to invalidate to update the color
+                    mLockScreenFp.addValueCallback(new KeyPath("**"), LottieProperty.COLOR_FILTER,
+                            frameInfo -> new PorterDuffColorFilter(mTextColorPrimary,
+                                    PorterDuff.Mode.SRC_ATOP));
+                    mOnFinishInflateRunnable.run();
+                }
+            };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
index 6ce6172..76bcd6e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
@@ -19,14 +19,12 @@
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Paint
-import android.graphics.PointF
 import android.graphics.Rect
 import android.graphics.RectF
 import android.util.AttributeSet
 import android.util.Log
 import android.view.MotionEvent
 import android.widget.FrameLayout
-import com.android.systemui.res.R
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
 import com.android.systemui.doze.DozeReceiver
 
@@ -39,10 +37,6 @@
     context: Context,
     attrs: AttributeSet?
 ) : FrameLayout(context, attrs), DozeReceiver {
-
-    // Use expanded overlay when feature flag is true, set by UdfpsViewController
-    var useExpandedOverlay: Boolean = false
-
     // sensorRect may be bigger than the sensor. True sensor dimensions are defined in
     // overlayParams.sensorBounds
     var sensorRect = Rect()
@@ -53,14 +47,6 @@
         textSize = 32f
     }
 
-    private val sensorTouchAreaCoefficient: Float =
-        context.theme.obtainStyledAttributes(attrs, R.styleable.UdfpsView, 0, 0).use { a ->
-            require(a.hasValue(R.styleable.UdfpsView_sensorTouchAreaCoefficient)) {
-                "UdfpsView must contain sensorTouchAreaCoefficient"
-            }
-            a.getFloat(R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f)
-        }
-
     /** View controller (can be different for enrollment, BiometricPrompt, Keyguard, etc.). */
     var animationViewController: UdfpsAnimationViewController<*>? = null
 
@@ -94,22 +80,8 @@
     override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
         super.onLayout(changed, left, top, right, bottom)
 
-        val paddingX = animationViewController?.paddingX ?: 0
-        val paddingY = animationViewController?.paddingY ?: 0
-
         // Updates sensor rect in relation to the overlay view
-        if (useExpandedOverlay) {
-            animationViewController?.onSensorRectUpdated(RectF(sensorRect))
-        } else {
-            sensorRect.set(
-                    paddingX,
-                    paddingY,
-                    (overlayParams.sensorBounds.width() + paddingX),
-                    (overlayParams.sensorBounds.height() + paddingY)
-            )
-
-            animationViewController?.onSensorRectUpdated(RectF(sensorRect))
-        }
+        animationViewController?.onSensorRectUpdated(RectF(sensorRect))
     }
 
     override fun onAttachedToWindow() {
@@ -131,22 +103,6 @@
         }
     }
 
-    fun isWithinSensorArea(x: Float, y: Float): Boolean {
-        // The X and Y coordinates of the sensor's center.
-        val translation = animationViewController?.touchTranslation ?: PointF(0f, 0f)
-        val cx = sensorRect.centerX() + translation.x
-        val cy = sensorRect.centerY() + translation.y
-        // Radii along the X and Y axes.
-        val rx = (sensorRect.right - sensorRect.left) / 2.0f
-        val ry = (sensorRect.bottom - sensorRect.top) / 2.0f
-
-        return x > cx - rx * sensorTouchAreaCoefficient &&
-            x < cx + rx * sensorTouchAreaCoefficient &&
-            y > cy - ry * sensorTouchAreaCoefficient &&
-            y < cy + ry * sensorTouchAreaCoefficient &&
-            !(animationViewController?.shouldPauseAuth() ?: false)
-    }
-
     fun configureDisplay(onDisplayConfigured: Runnable) {
         isDisplayConfigured = true
         animationViewController?.onDisplayConfiguring()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
index 943216e..b2a7607 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
@@ -17,6 +17,8 @@
 package com.android.systemui.bouncer.data.repository
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -24,11 +26,18 @@
 
 /** Provides access to bouncer-related application state. */
 @SysUISingleton
-class BouncerRepository @Inject constructor() {
+class BouncerRepository
+@Inject
+constructor(
+    flags: FeatureFlagsClassic,
+) {
     private val _message = MutableStateFlow<String?>(null)
     /** The user-facing message to show in the bouncer. */
     val message: StateFlow<String?> = _message.asStateFlow()
 
+    /** Whether the user switcher should be displayed within the bouncer UI on large screens. */
+    val isUserSwitcherVisible: Boolean = flags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)
+
     fun setMessage(message: String?) {
         _message.value = message
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 0c02369..4ce1422 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -96,6 +96,9 @@
     /** Whether the pattern should be visible for the currently-selected user. */
     val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible
 
+    /** Whether the user switcher should be displayed within the bouncer UI on large screens. */
+    val isUserSwitcherVisible: Boolean = repository.isUserSwitcherVisible
+
     init {
         if (flags.isEnabled()) {
             // Clear the message if moved from throttling to no-longer throttling.
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index 2cb98d8..ef0609a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -99,6 +99,8 @@
                 initialValue = emptyList(),
             )
 
+    val isUserSwitcherVisible: Boolean = bouncerInteractor.isUserSwitcherVisible
+
     private val isInputEnabled: StateFlow<Boolean> =
         bouncerInteractor.isThrottled
             .map { !it }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModel.kt
index 4efc21b..4b78e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModel.kt
@@ -35,10 +35,8 @@
  * The input is guaranteed to always contain a initial [ClearAll] token as a sentinel, thus clients
  * can always assume there is a 'ClearAll' watermark available.
  */
-data class PinInputViewModel
-internal constructor(
-    @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    internal val input: List<EntryToken>
+data class PinInputViewModel(
+    @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) val input: List<EntryToken>
 ) {
     init {
         require(input.firstOrNull() is ClearAll) { "input does not begin with a ClearAll token" }
@@ -132,8 +130,7 @@
     val sequenceNumber: Int
 
     /** The pin bouncer [input] as digits 0-9. */
-    data class Digit
-    internal constructor(val input: Int, override val sequenceNumber: Int = nextSequenceNumber++) :
+    data class Digit(val input: Int, override val sequenceNumber: Int = nextSequenceNumber++) :
         EntryToken {
         init {
             check(input in 0..9)
@@ -144,8 +141,7 @@
      * Marker to indicate the input is completely cleared, and subsequent [EntryToken]s mark a new
      * pin entry.
      */
-    data class ClearAll
-    internal constructor(override val sequenceNumber: Int = nextSequenceNumber++) : EntryToken
+    data class ClearAll(override val sequenceNumber: Int = nextSequenceNumber++) : EntryToken
 
     override fun compareTo(other: EntryToken): Int =
         compareValuesBy(this, other, EntryToken::sequenceNumber)
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index c0ee71c..0dfaf0f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -18,8 +18,15 @@
 
 import android.view.MotionEvent;
 
+import javax.inject.Inject;
+
 /** */
 public class FalsingCollectorFake implements FalsingCollector {
+
+    @Inject
+    public FalsingCollectorFake() {
+    }
+
     @Override
     public void onSuccessfulUnlock() {
     }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
index f6e0296..53b6879 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
@@ -15,7 +15,10 @@
 class CommunalRepositoryImpl
 @Inject
 constructor(
-    featureFlags: FeatureFlagsClassic,
+    private val featureFlags: FeatureFlagsClassic,
 ) : CommunalRepository {
-    override val isCommunalEnabled = featureFlags.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED)
+    override val isCommunalEnabled: Boolean
+        get() =
+            featureFlags.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) &&
+                featureFlags.isEnabled(Flags.COMMUNAL_HUB)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt
new file mode 100644
index 0000000..9a9b0e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 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.communal.data.repository
+
+import android.provider.Settings
+import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED
+import android.provider.Settings.Secure.HubModeTutorialState
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+/**
+ * Repository for the current state of hub mode tutorial. Valid states are defined in
+ * [HubModeTutorialState].
+ */
+interface CommunalTutorialRepository {
+    /** Emits the tutorial state stored in Settings */
+    val tutorialSettingState: StateFlow<Int>
+
+    /** Update the tutorial state */
+    suspend fun setTutorialState(@HubModeTutorialState state: Int)
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class CommunalTutorialRepositoryImpl
+@Inject
+constructor(
+    @Application private val applicationScope: CoroutineScope,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    userRepository: UserRepository,
+    private val secureSettings: SecureSettings,
+    private val userTracker: UserTracker,
+    @CommunalLog logBuffer: LogBuffer,
+) : CommunalTutorialRepository {
+
+    companion object {
+        private const val TAG = "CommunalTutorialRepository"
+    }
+
+    private data class SettingsState(
+        @HubModeTutorialState val hubModeTutorialState: Int? = null,
+    )
+
+    private val logger = Logger(logBuffer, TAG)
+
+    private val settingsState: Flow<SettingsState> =
+        userRepository.selectedUserInfo
+            .flatMapLatest { observeSettings() }
+            .shareIn(scope = applicationScope, started = SharingStarted.WhileSubscribed())
+
+    /** Emits the state of tutorial state in settings */
+    override val tutorialSettingState: StateFlow<Int> =
+        settingsState
+            .map { it.hubModeTutorialState }
+            .filterNotNull()
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = HUB_MODE_TUTORIAL_NOT_STARTED
+            )
+
+    private fun observeSettings(): Flow<SettingsState> =
+        secureSettings
+            .observerFlow(
+                userId = userTracker.userId,
+                names =
+                    arrayOf(
+                        Settings.Secure.HUB_MODE_TUTORIAL_STATE,
+                    )
+            )
+            // Force an update
+            .onStart { emit(Unit) }
+            .map { readFromSettings() }
+
+    private suspend fun readFromSettings(): SettingsState =
+        withContext(backgroundDispatcher) {
+            val userId = userTracker.userId
+            val hubModeTutorialState =
+                secureSettings.getIntForUser(
+                    Settings.Secure.HUB_MODE_TUTORIAL_STATE,
+                    HUB_MODE_TUTORIAL_NOT_STARTED,
+                    userId,
+                )
+            val settingsState = SettingsState(hubModeTutorialState)
+            logger.d({ "Communal tutorial state for user $int1 in settings: $str1" }) {
+                int1 = userId
+                str1 = settingsState.hubModeTutorialState.toString()
+            }
+
+            settingsState
+        }
+
+    override suspend fun setTutorialState(state: Int): Unit =
+        withContext(backgroundDispatcher) {
+            val userId = userTracker.userId
+            if (tutorialSettingState.value == state) {
+                return@withContext
+            }
+            logger.d({ "Update communal tutorial state to $int1 for user $int2" }) {
+                int1 = state
+                int2 = userId
+            }
+            secureSettings.putIntForUser(
+                Settings.Secure.HUB_MODE_TUTORIAL_STATE,
+                state,
+                userId,
+            )
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryModule.kt
new file mode 100644
index 0000000..69b0a27
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryModule.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 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.communal.data.repository
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface CommunalTutorialRepositoryModule {
+    @Binds
+    fun communalTutorialRepository(impl: CommunalTutorialRepositoryImpl): CommunalTutorialRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 9fb8da3..04bb6ae 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -28,11 +28,13 @@
 class CommunalInteractor
 @Inject
 constructor(
-    communalRepository: CommunalRepository,
+    private val communalRepository: CommunalRepository,
     widgetRepository: CommunalWidgetRepository,
 ) {
+
     /** Whether communal features are enabled. */
-    val isCommunalEnabled: Boolean = communalRepository.isCommunalEnabled
+    val isCommunalEnabled: Boolean
+        get() = communalRepository.isCommunalEnabled
 
     /** A flow of info about the widget to be displayed, or null if widget is unavailable. */
     val appWidgetInfo: Flow<CommunalAppWidgetInfo?> = widgetRepository.stopwatchAppWidgetInfo
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractor.kt
new file mode 100644
index 0000000..276df4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractor.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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.communal.domain.interactor
+
+import android.provider.Settings
+import com.android.systemui.communal.data.repository.CommunalTutorialRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+
+/** Encapsulates business-logic related to communal tutorial state. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class CommunalTutorialInteractor
+@Inject
+constructor(
+    communalTutorialRepository: CommunalTutorialRepository,
+    keyguardInteractor: KeyguardInteractor,
+) {
+    /** An observable for whether the tutorial is available. */
+    val isTutorialAvailable: Flow<Boolean> =
+        combine(
+                keyguardInteractor.isKeyguardVisible,
+                communalTutorialRepository.tutorialSettingState,
+            ) { isKeyguardVisible, tutorialSettingState ->
+                isKeyguardVisible &&
+                    tutorialSettingState != Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED
+            }
+            .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalTutorialIndicatorViewBinder.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalTutorialIndicatorViewBinder.kt
new file mode 100644
index 0000000..dab6819
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalTutorialIndicatorViewBinder.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 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.communal.ui.binder
+
+import android.widget.TextView
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.launch
+
+/** View binder for communal tutorial indicator shown on keyguard. */
+object CommunalTutorialIndicatorViewBinder {
+    fun bind(
+        view: TextView,
+        viewModel: CommunalTutorialIndicatorViewModel,
+    ): DisposableHandle {
+        val disposableHandle =
+            view.repeatWhenAttached {
+                repeatOnLifecycle(Lifecycle.State.STARTED) {
+                    launch {
+                        viewModel.showIndicator.collect { isVisible ->
+                            updateView(
+                                view = view,
+                                isIndicatorVisible = isVisible,
+                            )
+                        }
+                    }
+                }
+            }
+
+        return disposableHandle
+    }
+
+    private fun updateView(
+        isIndicatorVisible: Boolean,
+        view: TextView,
+    ) {
+        if (!isIndicatorVisible) {
+            view.isGone = true
+            return
+        }
+
+        if (!view.isVisible) {
+            view.isVisible = true
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalTutorialIndicatorSection.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalTutorialIndicatorSection.kt
new file mode 100644
index 0000000..027cc96
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalTutorialIndicatorSection.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2023 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.communal.ui.view.layout.sections
+
+import android.content.res.Resources
+import android.graphics.Typeface
+import android.graphics.Typeface.NORMAL
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.core.content.res.ResourcesCompat
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.ui.binder.CommunalTutorialIndicatorViewBinder
+import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewModel
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.view.layout.sections.removeView
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
+
+class CommunalTutorialIndicatorSection
+@Inject
+constructor(
+    @Main private val resources: Resources,
+    private val communalTutorialIndicatorViewModel: CommunalTutorialIndicatorViewModel,
+    private val communalInteractor: CommunalInteractor,
+) : KeyguardSection() {
+    private var communalTutorialIndicatorHandle: DisposableHandle? = null
+
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (!communalInteractor.isCommunalEnabled) {
+            return
+        }
+        val padding =
+            constraintLayout.resources.getDimensionPixelSize(
+                R.dimen.communal_tutorial_indicator_padding
+            )
+        val view =
+            TextView(constraintLayout.context).apply {
+                id = R.id.communal_tutorial_indicator
+                visibility = View.GONE
+                background =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_bg,
+                        context.theme
+                    )
+                foreground =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_selected_border,
+                        context.theme
+                    )
+                gravity = Gravity.CENTER_VERTICAL
+                typeface = Typeface.create("google-sans", NORMAL)
+                text = constraintLayout.context.getString(R.string.communal_tutorial_indicator_text)
+                setPadding(padding, padding, padding, padding)
+            }
+        constraintLayout.addView(view)
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (!communalInteractor.isCommunalEnabled) {
+            return
+        }
+        communalTutorialIndicatorHandle =
+            CommunalTutorialIndicatorViewBinder.bind(
+                constraintLayout.requireViewById(R.id.communal_tutorial_indicator),
+                communalTutorialIndicatorViewModel,
+            )
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
+        if (!communalInteractor.isCommunalEnabled) {
+            return
+        }
+        val tutorialIndicatorId = R.id.communal_tutorial_indicator
+        val width = resources.getDimensionPixelSize(R.dimen.communal_tutorial_indicator_fixed_width)
+        val horizontalOffsetMargin =
+            resources.getDimensionPixelSize(R.dimen.communal_tutorial_indicator_horizontal_offset)
+
+        constraintSet.apply {
+            constrainWidth(tutorialIndicatorId, width)
+            constrainHeight(tutorialIndicatorId, WRAP_CONTENT)
+            connect(
+                tutorialIndicatorId,
+                ConstraintSet.RIGHT,
+                ConstraintSet.PARENT_ID,
+                ConstraintSet.RIGHT,
+                horizontalOffsetMargin
+            )
+            connect(
+                tutorialIndicatorId,
+                ConstraintSet.TOP,
+                ConstraintSet.PARENT_ID,
+                ConstraintSet.TOP
+            )
+            connect(
+                tutorialIndicatorId,
+                ConstraintSet.BOTTOM,
+                ConstraintSet.PARENT_ID,
+                ConstraintSet.BOTTOM
+            )
+        }
+    }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        communalTutorialIndicatorHandle?.dispose()
+        constraintLayout.removeView(R.id.communal_tutorial_indicator)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTutorialIndicatorViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTutorialIndicatorViewModel.kt
new file mode 100644
index 0000000..eaf9550
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTutorialIndicatorViewModel.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.communal.ui.viewmodel
+
+import com.android.systemui.communal.domain.interactor.CommunalTutorialInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** View model for communal tutorial indicator on keyguard */
+class CommunalTutorialIndicatorViewModel
+@Inject
+constructor(
+    communalTutorialInteractor: CommunalTutorialInteractor,
+) {
+    /** An observable for whether the tutorial indicator view should be visible. */
+    val showIndicator: Flow<Boolean> = communalTutorialInteractor.isTutorialAvailable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImpl.kt
index 8e3b510..436b8cb 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImpl.kt
@@ -22,7 +22,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.qs.SettingObserver
+import com.android.systemui.qs.UserSettingObserver
 import com.android.systemui.user.data.repository.UserRepository
 import com.android.systemui.util.settings.SecureSettings
 import javax.inject.Inject
@@ -64,7 +64,8 @@
             .flatMapLatest { userInfo ->
                 conflatedCallbackFlow {
                         val observer =
-                            object : SettingObserver(secureSettings, null, setting, userInfo.id) {
+                            object :
+                                UserSettingObserver(secureSettings, null, setting, userInfo.id) {
                                 override fun handleValueChanged(
                                     value: Int,
                                     observedChange: Boolean
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index 046ccf16..a90980f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -18,7 +18,6 @@
 
 import com.android.systemui.globalactions.ShutdownUiModule;
 import com.android.systemui.keyguard.CustomizationProvider;
-import com.android.systemui.shade.ShadeModule;
 import com.android.systemui.statusbar.NotificationInsetsModule;
 import com.android.systemui.statusbar.QsFrameTranslateModule;
 
@@ -33,7 +32,6 @@
         DependencyProvider.class,
         NotificationInsetsModule.class,
         QsFrameTranslateModule.class,
-        ShadeModule.class,
         ShutdownUiModule.class,
         SystemUIBinder.class,
         SystemUIModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 9e5fd55..1dd4abf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -21,12 +21,9 @@
 
 import android.content.Context;
 import android.hardware.SensorPrivacyManager;
-import android.os.Handler;
 
-import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardViewController;
 import com.android.systemui.battery.BatterySaverModule;
-import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
 import com.android.systemui.doze.DozeHost;
@@ -34,7 +31,6 @@
 import com.android.systemui.navigationbar.NavigationBarControllerModule;
 import com.android.systemui.navigationbar.gestural.GestureModule;
 import com.android.systemui.plugins.qs.QSFactory;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.dagger.PowerModule;
 import com.android.systemui.qs.dagger.QSModule;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
@@ -45,7 +41,7 @@
 import com.android.systemui.screenshot.ReferenceScreenshotModule;
 import com.android.systemui.settings.dagger.MultiUserUtilsModule;
 import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
-import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeModule;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyboardShortcutsModule;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -53,20 +49,13 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule;
 import com.android.systemui.statusbar.events.StatusBarEventsModule;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.phone.DozeServiceHost;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.HeadsUpModule;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentStartableModule;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.AospPolicyModule;
-import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyControllerImpl;
 import com.android.systemui.statusbar.policy.SensorPrivacyController;
@@ -100,11 +89,13 @@
         BatterySaverModule.class,
         CollapsedStatusBarFragmentStartableModule.class,
         GestureModule.class,
+        HeadsUpModule.class,
         MediaModule.class,
         MultiUserUtilsModule.class,
         NavigationBarControllerModule.class,
         PowerModule.class,
         QSModule.class,
+        ShadeModule.class,
         ReferenceScreenshotModule.class,
         RotationLockModule.class,
         SceneContainerFrameworkModule.class,
@@ -161,38 +152,6 @@
         return true;
     }
 
-    @SysUISingleton
-    @Provides
-    static HeadsUpManagerPhone provideHeadsUpManagerPhone(
-            Context context,
-            HeadsUpManagerLogger headsUpManagerLogger,
-            StatusBarStateController statusBarStateController,
-            KeyguardBypassController bypassController,
-            GroupMembershipManager groupManager,
-            VisualStabilityProvider visualStabilityProvider,
-            ConfigurationController configurationController,
-            @Main Handler handler,
-            AccessibilityManagerWrapper accessibilityManagerWrapper,
-            UiEventLogger uiEventLogger,
-            ShadeExpansionStateManager shadeExpansionStateManager) {
-        return new HeadsUpManagerPhone(
-                context,
-                headsUpManagerLogger,
-                statusBarStateController,
-                bypassController,
-                groupManager,
-                visualStabilityProvider,
-                configurationController,
-                handler,
-                accessibilityManagerWrapper,
-                uiEventLogger,
-                shadeExpansionStateManager
-        );
-    }
-
-    @Binds
-    abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
-
     @Provides
     @SysUISingleton
     static Recents provideRecents(Context context, RecentsImplementation recentsImplementation,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index d89332d..5d6949b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.keyguard.KeyguardViewConfigurator
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable
+import com.android.systemui.keyguard.ui.binder.AlternateBouncerBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardDismissActionBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardDismissBinder
 import com.android.systemui.log.SessionTracker
@@ -92,6 +93,11 @@
     @ClassKey(AuthController::class)
     abstract fun bindAuthController(service: AuthController): CoreStartable
 
+    @Binds
+    @IntoMap
+    @ClassKey(AlternateBouncerBinder::class)
+    abstract fun bindAlternateBouncerBinder(impl: AlternateBouncerBinder): CoreStartable
+
     /** Inject into BiometricNotificationService */
     @Binds
     @IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 4b6ad6d..7d4e1a1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -33,7 +33,6 @@
 import com.android.systemui.appops.dagger.AppOpsModule;
 import com.android.systemui.assist.AssistModule;
 import com.android.systemui.authentication.AuthenticationModule;
-import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
 import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
 import com.android.systemui.biometrics.FingerprintReEnrollNotification;
 import com.android.systemui.biometrics.UdfpsDisplayModeProvider;
@@ -56,6 +55,7 @@
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.FlagsModule;
 import com.android.systemui.keyboard.KeyboardModule;
+import com.android.systemui.keyevent.data.repository.KeyEventRepositoryModule;
 import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule;
 import com.android.systemui.log.dagger.LogModule;
 import com.android.systemui.log.dagger.MonitorLog;
@@ -181,6 +181,7 @@
         FalsingModule.class,
         FlagsModule.class,
         FooterActionsModule.class,
+        KeyEventRepositoryModule.class,
         KeyboardModule.class,
         KeyguardBlueprintModule.class,
         LetterboxModule.class,
@@ -298,9 +299,6 @@
     abstract UdfpsDisplayModeProvider optionalUdfpsDisplayModeProvider();
 
     @BindsOptionalOf
-    abstract AlternateUdfpsTouchProvider optionalUdfpsTouchProvider();
-
-    @BindsOptionalOf
     abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider();
 
     @BindsOptionalOf
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt
index 5b85ad0..1e29e1f 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt
@@ -2,7 +2,7 @@
 
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
@@ -51,7 +51,7 @@
      * When this is `false`, an automatically-triggered face unlock shouldn't automatically dismiss
      * the lockscreen.
      */
-    fun isBypassEnabled(): Boolean
+    val isBypassEnabled: StateFlow<Boolean>
 }
 
 /** Encapsulates application state for device entry. */
@@ -68,7 +68,7 @@
 ) : DeviceEntryRepository {
 
     override val isUnlocked =
-        ConflatedCallbackFlow.conflatedCallbackFlow {
+        conflatedCallbackFlow {
                 val callback =
                     object : KeyguardStateController.Callback {
                         override fun onUnlockedChanged() {
@@ -112,7 +112,24 @@
         }
     }
 
-    override fun isBypassEnabled() = keyguardBypassController.bypassEnabled
+    override val isBypassEnabled: StateFlow<Boolean> =
+        conflatedCallbackFlow {
+                val listener =
+                    object : KeyguardBypassController.OnBypassStateChangedListener {
+                        override fun onBypassStateChanged(isEnabled: Boolean) {
+                            trySend(isEnabled)
+                        }
+                    }
+                keyguardBypassController.registerOnBypassStateChangedListener(listener)
+                awaitClose {
+                    keyguardBypassController.unregisterOnBypassStateChangedListener(listener)
+                }
+            }
+            .stateIn(
+                applicationScope,
+                SharingStarted.Eagerly,
+                initialValue = keyguardBypassController.bypassEnabled,
+            )
 
     companion object {
         private const val TAG = "DeviceEntryRepositoryImpl"
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 5612c9a..e96e318 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -106,5 +106,5 @@
      * authentication challenge via face unlock or fingerprint sensor can automatically bypass the
      * lock screen.
      */
-    fun isBypassEnabled() = repository.isBypassEnabled()
+    val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
index 126a1b5..6946950 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
@@ -31,7 +31,6 @@
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.os.Bundle;
-import android.os.UserHandle;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -48,6 +47,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
@@ -55,15 +55,15 @@
 
 /**
  * Concrete implementation of the a Flag manager that returns default values for debug builds
- *
+ * <p>
  * Flags can be set (or unset) via the following adb command:
- *
+ * <p>
  * adb shell cmd statusbar flag <id> <on|off|toggle|erase>
- *
+ * <p>
  * Alternatively, you can change flags via a broadcast intent:
- *
+ * <p>
  * adb shell am broadcast -a com.android.systemui.action.SET_FLAG --ei id <id> [--ez value <0|1>]
- *
+ * <p>
  * To restore a flag back to its default, leave the `--ez value <0|1>` off of the command.
  */
 @SysUISingleton
@@ -77,9 +77,9 @@
     private final SystemPropertiesHelper mSystemProperties;
     private final ServerFlagReader mServerFlagReader;
     private final Map<String, Flag<?>> mAllFlags;
-    private final Map<String, Boolean> mBooleanFlagCache = new TreeMap<>();
-    private final Map<String, String> mStringFlagCache = new TreeMap<>();
-    private final Map<String, Integer> mIntFlagCache = new TreeMap<>();
+    private final Map<String, Boolean> mBooleanFlagCache = new ConcurrentHashMap<>();
+    private final Map<String, String> mStringFlagCache = new ConcurrentHashMap<>();
+    private final Map<String, Integer> mIntFlagCache = new ConcurrentHashMap<>();
     private final Restarter mRestarter;
 
     private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
@@ -160,87 +160,92 @@
 
     private boolean isEnabledInternal(@NotNull BooleanFlag flag) {
         String name = flag.getName();
-        if (!mBooleanFlagCache.containsKey(name)) {
-            mBooleanFlagCache.put(name,
-                    readBooleanFlagInternal(flag, flag.getDefault()));
+
+        Boolean value = mBooleanFlagCache.get(name);
+        if (value == null) {
+            value = readBooleanFlagInternal(flag, flag.getDefault());
+            mBooleanFlagCache.put(name, value);
         }
 
-        return mBooleanFlagCache.get(name);
+        return value;
     }
 
     @Override
     public boolean isEnabled(@NonNull ResourceBooleanFlag flag) {
         String name = flag.getName();
-        if (!mBooleanFlagCache.containsKey(name)) {
-            mBooleanFlagCache.put(name,
-                    readBooleanFlagInternal(flag, mResources.getBoolean(flag.getResourceId())));
+        Boolean value = mBooleanFlagCache.get(name);
+        if (value == null) {
+            value = readBooleanFlagInternal(flag, mResources.getBoolean(flag.getResourceId()));
+            mBooleanFlagCache.put(name, value);
         }
 
-        return mBooleanFlagCache.get(name);
+        return value;
     }
 
     @Override
     public boolean isEnabled(@NonNull SysPropBooleanFlag flag) {
         String name = flag.getName();
-        if (!mBooleanFlagCache.containsKey(name)) {
-            // Use #readFlagValue to get the default. That will allow it to fall through to
-            // teamfood if need be.
-            mBooleanFlagCache.put(
-                    name,
+        Boolean value = mBooleanFlagCache.get(name);
+        if (value == null) {
+            value = readBooleanFlagInternal(flag,
                     mSystemProperties.getBoolean(
                             flag.getName(),
                             readBooleanFlagInternal(flag, flag.getDefault())));
+            mBooleanFlagCache.put(name, value);
         }
-
-        return mBooleanFlagCache.get(name);
+        return value;
     }
 
     @NonNull
     @Override
     public String getString(@NonNull StringFlag flag) {
         String name = flag.getName();
-        if (!mStringFlagCache.containsKey(name)) {
-            mStringFlagCache.put(name,
-                    readFlagValueInternal(name, flag.getDefault(), StringFlagSerializer.INSTANCE));
+        String value = mStringFlagCache.get(name);
+        if (value == null) {
+            value = readFlagValueInternal(name, flag.getDefault(), StringFlagSerializer.INSTANCE);
+            mStringFlagCache.put(name, value);
         }
 
-        return mStringFlagCache.get(name);
+        return value;
     }
 
     @NonNull
     @Override
     public String getString(@NonNull ResourceStringFlag flag) {
         String name = flag.getName();
-        if (!mStringFlagCache.containsKey(name)) {
-            mStringFlagCache.put(name,
-                    readFlagValueInternal(name, mResources.getString(flag.getResourceId()),
-                            StringFlagSerializer.INSTANCE));
+        String value = mStringFlagCache.get(name);
+        if (value == null) {
+            value = readFlagValueInternal(
+                    name,
+                    mResources.getString(flag.getResourceId()),
+                    StringFlagSerializer.INSTANCE);
+            mStringFlagCache.put(name, value);
         }
-
-        return mStringFlagCache.get(name);
+        return value;
     }
 
     @Override
     public int getInt(@NonNull IntFlag flag) {
         String name = flag.getName();
-        if (!mIntFlagCache.containsKey(name)) {
-            mIntFlagCache.put(name,
-                    readFlagValueInternal(name, flag.getDefault(), IntFlagSerializer.INSTANCE));
+        Integer value = mIntFlagCache.get(name);
+        if (value == null) {
+            value = readFlagValueInternal(name, flag.getDefault(), IntFlagSerializer.INSTANCE);
+            mIntFlagCache.put(name, value);
         }
 
-        return mIntFlagCache.get(name);
+        return value;
     }
 
     @Override
     public int getInt(@NonNull ResourceIntFlag flag) {
         String name = flag.getName();
-        if (!mIntFlagCache.containsKey(name)) {
-            mIntFlagCache.put(name,
-                    readFlagValueInternal(name, mResources.getInteger(flag.getResourceId()),
-                            IntFlagSerializer.INSTANCE));
+        Integer value = mIntFlagCache.get(name);
+        if (value == null) {
+            value = readFlagValueInternal(
+                    name, mResources.getInteger(flag.getResourceId()), IntFlagSerializer.INSTANCE);
+            mIntFlagCache.put(name, value);
         }
-
-        return mIntFlagCache.get(name);
+        return value;
     }
 
     /** Specific override for Boolean flags that checks against the teamfood list.*/
@@ -313,8 +318,7 @@
             Log.w(TAG, "Failed to set flag " + name + " to " + value);
             return;
         }
-        mGlobalSettings.putStringForUser(mFlagManager.nameToSettingsKey(name), data,
-                UserHandle.USER_CURRENT);
+        mGlobalSettings.putString(mFlagManager.nameToSettingsKey(name), data);
     }
 
     <T> void eraseFlag(Flag<T> flag) {
@@ -348,8 +352,7 @@
     /** Works just like {@link #eraseFlag(String)} except that it doesn't restart SystemUI. */
     private void eraseInternal(String name) {
         // We can't actually "erase" things from settings, but we can set them to empty!
-        mGlobalSettings.putStringForUser(mFlagManager.nameToSettingsKey(name), "",
-                UserHandle.USER_CURRENT);
+        mGlobalSettings.putString(mFlagManager.nameToSettingsKey(name), "");
         Log.i(TAG, "Erase name " + name);
     }
 
@@ -531,11 +534,22 @@
     @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("can override: true");
+
         pw.println("booleans: " + mBooleanFlagCache.size());
-        mBooleanFlagCache.forEach((key, value) -> pw.println("  sysui_flag_" + key + ": " + value));
+        // Sort our flags for dumping
+        TreeMap<String, Boolean> dumpBooleanMap = new TreeMap<>(mBooleanFlagCache);
+        dumpBooleanMap.forEach((key, value) -> pw.println("  sysui_flag_" + key + ": " + value));
+
         pw.println("Strings: " + mStringFlagCache.size());
-        mStringFlagCache.forEach((key, value) -> pw.println("  sysui_flag_" + key
+        // Sort our flags for dumping
+        TreeMap<String, String> dumpStringMap = new TreeMap<>(mStringFlagCache);
+        dumpStringMap.forEach((key, value) -> pw.println("  sysui_flag_" + key
                 + ": [length=" + value.length() + "] \"" + value + "\""));
+
+        pw.println("Integers: " + mIntFlagCache.size());
+        // Sort our flags for dumping
+        TreeMap<String, Integer> dumpIntMap = new TreeMap<>(mIntFlagCache);
+        dumpIntMap.forEach((key, value) -> pw.println("  sysui_flag_" + key + ": " + value));
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
index e3cc2b0..bf9018a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
@@ -177,6 +177,13 @@
                 || (flag instanceof SysPropFlag);
     }
 
+    private Boolean isTeamfoodFlag(Flag<?>  flag) {
+        if (!(flag instanceof BooleanFlag)) {
+            return null;
+        }
+        return flag.getTeamfood();
+    }
+
     private boolean isBooleanFlagEnabled(Flag<?> flag) {
         if (flag instanceof ReleasedFlag) {
             return mFeatureFlags.isEnabled((ReleasedFlag) flag);
@@ -232,11 +239,13 @@
         for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
             pw.print(" ");
         }
-        pw.println(" Value");
+        pw.print(" Value  ");
+        pw.println(" Teamfood?");
         for (int i = 0; i < longestFieldName; i++) {
             pw.print("=");
         }
-        pw.println(" ========");
+        pw.println(" ======= ===========");
+
         for (String fieldName : fields.keySet()) {
             Flag<?> flag = fields.get(fieldName);
             if (!mAllFlags.containsKey(flag.getName())) {
@@ -249,7 +258,19 @@
             }
             pw.print(" ");
             if (isBooleanFlag(flag)) {
-                pw.println(isBooleanFlagEnabled(flag));
+                boolean enabled = isBooleanFlagEnabled(flag);
+                pw.print(enabled);
+                if (enabled) {
+                    pw.print("    ");
+                } else {
+                    pw.print("   ");
+                }
+                Boolean teamfood = isTeamfoodFlag(flag);
+                if (teamfood != null) {
+                    pw.print(teamfood);
+                }
+                pw.println();
+
             } else if (isStringFlag(flag)) {
                 pw.println(getStringFlag(flag));
             } else if (isIntFlag(flag)) {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 8587329..c7f4afc 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -40,8 +40,8 @@
 
     // 100 - notification
     // TODO(b/297792660): Tracking Bug
-    val ADD_TRANSIENT_HUN_IN_STACK_STATE_ANIMATOR =
-        unreleasedFlag("add_transient_hun_in_stack_state_animator", teamfood = false)
+    @JvmField val UNCLEARED_TRANSIENT_HUN_FIX =
+        unreleasedFlag("uncleared_transient_hun_fix", teamfood = false)
 
     // TODO(b/298308067): Tracking Bug
     @JvmField val SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX =
@@ -144,11 +144,6 @@
             "lockscreen_custom_clocks"
         )
 
-    // TODO(b/275694445): Tracking Bug
-    @JvmField
-    val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING =
-        releasedFlag("lockscreen_without_secure_lock_when_dreaming")
-
     // TODO(b/286092087): Tracking Bug
     @JvmField
     val ENABLE_SYSTEM_UI_DREAM_CONTROLLER = unreleasedFlag("enable_system_ui_dream_controller")
@@ -176,7 +171,11 @@
      */
     // TODO(b/281655028): Tracking bug
     @JvmField
-    val LIGHT_REVEAL_MIGRATION = unreleasedFlag("light_reveal_migration", teamfood = false)
+    val LIGHT_REVEAL_MIGRATION = unreleasedFlag("light_reveal_migration", teamfood = true)
+
+    // TODO(b/301915812): Tracking Bug
+    @JvmField
+    val NEW_AOD_TRANSITION = unreleasedFlag("new_aod_transition", teamfood = true)
 
     /** Flag to control the migration of face auth to modern architecture. */
     // TODO(b/262838215): Tracking bug
@@ -230,8 +229,7 @@
     /** Whether page transition animations in the wallpaper picker are enabled */
     // TODO(b/291710220): Tracking bug.
     @JvmField
-    val WALLPAPER_PICKER_PAGE_TRANSITIONS =
-        unreleasedFlag("wallpaper_picker_page_transitions", teamfood = true)
+    val WALLPAPER_PICKER_PAGE_TRANSITIONS = releasedFlag("wallpaper_picker_page_transitions")
 
     /** Add "Apply" button to wall paper picker's grid preview page. */
     // TODO(b/294866904): Tracking bug.
@@ -306,6 +304,11 @@
     @JvmField
     val WALLPAPER_PICKER_PREVIEW_ANIMATION = releasedFlag("wallpaper_picker_preview_animation")
 
+    /** Flag to enable rest to unlock feature. */
+    // TODO(b/303672286): Tracking bug
+    @JvmField
+    val REST_TO_UNLOCK: UnreleasedFlag = unreleasedFlag("rest_to_unlock")
+
     /**
      * TODO(b/278086361): Tracking bug
      * Complete rewrite of the interactions between System UI and Window Manager involving keyguard
@@ -328,7 +331,7 @@
     /** Flag to use a separate view for the alternate bouncer. */
     // TODO(b/300440924): Tracking bug
     @JvmField
-    val ALTERNATE_BOUNCER_REFACTOR: UnreleasedFlag = unreleasedFlag("alternate_bouncer_view")
+    val ALTERNATE_BOUNCER_VIEW: UnreleasedFlag = unreleasedFlag("alternate_bouncer_view")
 
     // 300 - power menu
     // TODO(b/254512600): Tracking Bug
@@ -664,8 +667,6 @@
     @JvmField val NOTE_TASKS = releasedFlag("keycode_flag")
 
     // 2200 - biometrics (udfps, sfps, BiometricPrompt, etc.)
-    // TODO(b/259264861): Tracking Bug
-    @JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag("udfps_new_touch_detection")
 
     // 2300 - stylus
     @JvmField val TRACK_STYLUS_EVER_USED = releasedFlag("track_stylus_ever_used")
@@ -783,8 +784,7 @@
 
     // TODO(b/290213663): Tracking Bug
     @JvmField
-    val ONE_WAY_HAPTICS_API_MIGRATION =
-            unreleasedFlag("oneway_haptics_api_migration", teamfood = true)
+    val ONE_WAY_HAPTICS_API_MIGRATION = releasedFlag("oneway_haptics_api_migration")
 
     /** TODO(b/296223317): Enables the new keyguard presentation containing a clock. */
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/flags/ViewRefactorFlag.kt b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlag.kt
similarity index 71%
rename from packages/SystemUI/src/com/android/systemui/flags/ViewRefactorFlag.kt
rename to packages/SystemUI/src/com/android/systemui/flags/RefactorFlag.kt
index eaecda5..3fe6806 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/ViewRefactorFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlag.kt
@@ -28,27 +28,23 @@
  *   flag-disabled builds, but with a check that should crash eng builds or tests when the
  *   expectation is violated.
  *
- * The constructors prefer that you provide a [FeatureFlags] instance, but does not require it,
+ * The constructors require that you provide a [FeatureFlags] instance. If you're using this in a
+ * View class, it's acceptable to ue the [forView] constructor methods, which do not require one,
  * falling back to [Dependency.get]. This fallback should ONLY be used to flag-guard code changes
- * inside views where injecting flag values after initialization can be error-prone.
+ * inside Views where injecting flag values after initialization can be error-prone.
  */
-class ViewRefactorFlag
+class RefactorFlag
 private constructor(
     private val injectedFlags: FeatureFlags?,
-    private val flag: BooleanFlag,
+    private val flagName: Any,
     private val readFlagValue: (FeatureFlags) -> Boolean
 ) {
-    @JvmOverloads
     constructor(
-        flags: FeatureFlags? = null,
+        flags: FeatureFlags,
         flag: UnreleasedFlag
     ) : this(flags, flag, { it.isEnabled(flag) })
 
-    @JvmOverloads
-    constructor(
-        flags: FeatureFlags? = null,
-        flag: ReleasedFlag
-    ) : this(flags, flag, { it.isEnabled(flag) })
+    constructor(flags: FeatureFlags, flag: ReleasedFlag) : this(flags, flag, { it.isEnabled(flag) })
 
     /** Whether the flag is enabled. Called to switch between an old behavior and a new behavior. */
     val isEnabled by lazy {
@@ -69,7 +65,8 @@
      * }
      * ````
      */
-    fun assertDisabled() = check(!isEnabled) { "Code path not supported when $flag is enabled." }
+    fun assertDisabled() =
+        check(!isEnabled) { "Code path not supported when $flagName is enabled." }
 
     /**
      * Called to ensure code is only run when the flag is enabled. This protects users from the
@@ -87,13 +84,25 @@
      */
     fun expectEnabled(): Boolean {
         if (!isEnabled) {
-            val message = "Code path not supported when $flag is disabled."
+            val message = "Code path not supported when $flagName is disabled."
             Log.wtf(TAG, message, Exception(message))
         }
         return isEnabled
     }
 
-    private companion object {
-        private const val TAG = "ViewRefactorFlag"
+    companion object {
+        private const val TAG = "RefactorFlag"
+
+        /** Construct a [RefactorFlag] within View construction where injection is impossible. */
+        @JvmStatic
+        @JvmOverloads
+        fun forView(flag: UnreleasedFlag, flags: FeatureFlags? = null) =
+            RefactorFlag(flags, flag) { it.isEnabled(flag) }
+
+        /** Construct a [RefactorFlag] within View construction where injection is impossible. */
+        @JvmStatic
+        @JvmOverloads
+        fun forView(flag: ReleasedFlag, flags: FeatureFlags? = null) =
+            RefactorFlag(flags, flag) { it.isEnabled(flag) }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index ac40230..c6c1f79 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -749,7 +749,7 @@
     @VisibleForTesting
     boolean shouldDisplayBugReport(@Nullable UserInfo user) {
         return user != null && user.isAdmin()
-                && mGlobalSettings.getIntForUser(Settings.Secure.BUGREPORT_IN_POWER_MENU, 0,
+                && mSecureSettings.getIntForUser(Settings.Secure.BUGREPORT_IN_POWER_MENU, 0,
                 user.id) != 0;
     }
 
@@ -1091,7 +1091,7 @@
 
         @Override
         public boolean showBeforeProvisioning() {
-            return Build.isDebuggable() && mGlobalSettings.getIntForUser(
+            return Build.isDebuggable() && mSecureSettings.getIntForUser(
                     Settings.Secure.BUGREPORT_IN_POWER_MENU, 0, getCurrentUser().id) != 0
                     && getCurrentUser().isAdmin();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt
new file mode 100644
index 0000000..5bc5d0b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.keyevent.data.repository
+
+import android.view.KeyEvent
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.CommandQueue
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Defines interface for classes that encapsulate application state for key event presses. */
+interface KeyEventRepository {
+    /** Observable for whether the power button key is pressed/down or not. */
+    val isPowerButtonDown: Flow<Boolean>
+}
+
+@SysUISingleton
+class KeyEventRepositoryImpl
+@Inject
+constructor(
+    val commandQueue: CommandQueue,
+) : KeyEventRepository {
+    override val isPowerButtonDown: Flow<Boolean> = conflatedCallbackFlow {
+        val callback =
+            object : CommandQueue.Callbacks {
+                override fun handleSystemKey(event: KeyEvent) {
+                    if (event.keyCode == KeyEvent.KEYCODE_POWER) {
+                        trySendWithFailureLogging(event.isDown, TAG, "updated isPowerButtonDown")
+                    }
+                }
+            }
+        commandQueue.addCallback(callback)
+        awaitClose { commandQueue.removeCallback(callback) }
+    }
+
+    companion object {
+        private const val TAG = "KeyEventRepositoryImpl"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryModule.kt
new file mode 100644
index 0000000..afba5db
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryModule.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 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.keyevent.data.repository
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface KeyEventRepositoryModule {
+    @Binds fun keyEventRepository(impl: KeyEventRepositoryImpl): KeyEventRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt
index 3f2f67d..9949fa5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt
@@ -13,55 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.android.systemui.keyevent.domain.interactor
 
-import android.view.KeyEvent
-import com.android.systemui.back.domain.interactor.BackActionInteractor
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor
+import com.android.systemui.keyevent.data.repository.KeyEventRepository
 import javax.inject.Inject
 
 /**
- * Sends key events to the appropriate interactors and then acts upon key events that haven't
- * already been handled but should be handled by SystemUI.
+ * Business logic for all key event state. This includes all key events, regardless of whether
+ * they've been handled or not by a consumer.
+ *
+ * For key events that SysUI wants to properly handle, see [SysUIKeyEventHandler].
  */
 @SysUISingleton
 class KeyEventInteractor
 @Inject
 constructor(
-    private val backActionInteractor: BackActionInteractor,
-    private val keyguardKeyEventInteractor: KeyguardKeyEventInteractor,
+    repository: KeyEventRepository,
 ) {
-    fun dispatchKeyEvent(event: KeyEvent): Boolean {
-        if (keyguardKeyEventInteractor.dispatchKeyEvent(event)) {
-            return true
-        }
-
-        when (event.keyCode) {
-            KeyEvent.KEYCODE_BACK -> {
-                if (event.handleAction()) {
-                    backActionInteractor.onBackRequested()
-                }
-                return true
-            }
-        }
-        return false
-    }
-
-    fun interceptMediaKey(event: KeyEvent): Boolean {
-        return keyguardKeyEventInteractor.interceptMediaKey(event)
-    }
-
-    fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
-        return keyguardKeyEventInteractor.dispatchKeyEventPreIme(event)
-    }
-
-    companion object {
-        // Most actions shouldn't be handled on the down event and instead handled on subsequent
-        // key events like ACTION_UP.
-        fun KeyEvent.handleAction(): Boolean {
-            return action != KeyEvent.ACTION_DOWN
-        }
-    }
+    val isPowerButtonDown = repository.isPowerButtonDown
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt
new file mode 100644
index 0000000..1febc79
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.keyevent.domain.interactor
+
+import android.view.KeyEvent
+import com.android.systemui.back.domain.interactor.BackActionInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor
+import javax.inject.Inject
+
+/**
+ * Sends key events to the appropriate interactors and then acts upon key events that haven't
+ * already been handled but should be handled by SystemUI.
+ *
+ * To observe any key event states, see [KeyEventInteractor].
+ */
+@SysUISingleton
+class SysUIKeyEventHandler
+@Inject
+constructor(
+    private val backActionInteractor: BackActionInteractor,
+    private val keyguardKeyEventInteractor: KeyguardKeyEventInteractor,
+) {
+    fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        if (keyguardKeyEventInteractor.dispatchKeyEvent(event)) {
+            return true
+        }
+
+        when (event.keyCode) {
+            KeyEvent.KEYCODE_BACK -> {
+                if (event.handleAction()) {
+                    backActionInteractor.onBackRequested()
+                }
+                return true
+            }
+        }
+        return false
+    }
+
+    fun interceptMediaKey(event: KeyEvent): Boolean {
+        return keyguardKeyEventInteractor.interceptMediaKey(event)
+    }
+
+    fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
+        return keyguardKeyEventInteractor.dispatchKeyEventPreIme(event)
+    }
+
+    companion object {
+        // Most actions shouldn't be handled on the down event and instead handled on subsequent
+        // key events like ACTION_UP.
+        fun KeyEvent.handleAction(): Boolean {
+            return action != KeyEvent.ACTION_DOWN
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index a1f0e77..b45613e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -269,6 +269,11 @@
                 }
             }
 
+            @Override
+            public void onTransitionConsumed(IBinder transition, boolean aborted)
+                    throws RemoteException {
+            }
+
             private static void initAlphaForAnimationTargets(@NonNull SurfaceControl.Transaction t,
                     @NonNull RemoteAnimationTarget[] targets) {
                 for (RemoteAnimationTarget target : targets) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index f500017..86bf368 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -82,7 +82,8 @@
                 val statusViewComponent =
                     keyguardStatusViewComponentFactory.build(
                         LayoutInflater.from(context).inflate(R.layout.keyguard_status_view, null)
-                            as KeyguardStatusView
+                            as KeyguardStatusView,
+                        context.display
                     )
                 val controller = statusViewComponent.keyguardStatusViewController
                 controller.init()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 7678f4d..39742a0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -171,6 +171,8 @@
 import com.android.systemui.wallpapers.data.repository.WallpaperRepository;
 import com.android.wm.shell.keyguard.KeyguardTransitions;
 
+import dagger.Lazy;
+
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -180,7 +182,8 @@
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
-import dagger.Lazy;
+
+
 import kotlinx.coroutines.CoroutineDispatcher;
 
 /**
@@ -1933,11 +1936,7 @@
     public void onDreamingStarted() {
         mUpdateMonitor.dispatchDreamingStarted();
         synchronized (this) {
-            final boolean alwaysShowKeyguard =
-                mFeatureFlags.isEnabled(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING);
-            if (mDeviceInteractive
-                && (alwaysShowKeyguard ||
-                mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()))) {
+            if (mDeviceInteractive) {
                 doKeyguardLaterLocked();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 03c166c..081edd1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -28,6 +28,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardViewController;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.keyguard.dagger.KeyguardDisplayModule;
 import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
@@ -38,6 +39,7 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingModule;
 import com.android.systemui.communal.data.repository.CommunalRepositoryModule;
+import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryModule;
 import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -95,11 +97,13 @@
         KeyguardUserSwitcherComponent.class},
         includes = {
             CommunalRepositoryModule.class,
+            CommunalTutorialRepositoryModule.class,
             CommunalWidgetRepositoryModule.class,
             FalsingModule.class,
             KeyguardDataQuickAffordanceModule.class,
             KeyguardRepositoryModule.class,
             KeyguardFaceAuthModule.class,
+            KeyguardDisplayModule.class,
             StartKeyguardTransitionModule.class,
             ResourceTrimmerModule.class,
         })
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 3ccf446..d06f31f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -32,6 +32,7 @@
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
 
 @SysUISingleton
 class FromAlternateBouncerTransitionInteractor
@@ -129,11 +130,11 @@
     override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
         return ValueAnimator().apply {
             interpolator = Interpolators.LINEAR
-            duration = TRANSITION_DURATION_MS
+            duration = TRANSITION_DURATION_MS.inWholeMilliseconds
         }
     }
 
     companion object {
-        private const val TRANSITION_DURATION_MS = 300L
+        val TRANSITION_DURATION_MS = 300.milliseconds
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
index e57c919..89aca76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
@@ -61,6 +61,7 @@
     fun onSwipeUpOnBouncer()
     fun onPrimaryBouncerUserInput()
     fun onAccessibilityAction()
+    fun onWalletLaunched()
 }
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
index d6987629..122c4c4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -21,7 +21,7 @@
 import android.view.KeyEvent
 import com.android.systemui.back.domain.interactor.BackActionInteractor
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor.Companion.handleAction
+import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler.Companion.handleAction
 import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.power.domain.interactor.PowerInteractor
@@ -37,7 +37,6 @@
 constructor(
     private val context: Context,
     private val statusBarStateController: StatusBarStateController,
-    private val keyguardInteractor: KeyguardInteractor,
     private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
     private val shadeController: ShadeController,
     private val mediaSessionLegacyHelperWrapper: MediaSessionLegacyHelperWrapper,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 1c43609..fbe26de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -34,16 +34,17 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.stateIn
-import javax.inject.Inject
 
 /** Encapsulates business-logic related to the keyguard transitions. */
 @SysUISingleton
@@ -176,18 +177,17 @@
             .map { step -> step.to }
             .stateIn(scope, SharingStarted.Eagerly, LOCKSCREEN)
 
-
     /**
      * Whether we're currently in a transition to a new [KeyguardState] and haven't yet completed
      * it.
      */
     val isInTransitionToAnyState =
-            combine(
-                    startedKeyguardTransitionStep,
-                    finishedKeyguardState,
-            ) { startedStep, finishedState ->
-                startedStep.to != finishedState
-            }
+        combine(
+            startedKeyguardTransitionStep,
+            finishedKeyguardState,
+        ) { startedStep, finishedState ->
+            startedStep.to != finishedState
+        }
 
     /**
      * The amount of transition into or out of the given [KeyguardState].
@@ -236,14 +236,9 @@
 
     /** Whether we're in a transition to the given [KeyguardState], but haven't yet completed it. */
     fun isInTransitionToState(
-            state: KeyguardState,
+        state: KeyguardState,
     ): Flow<Boolean> {
-        return combine(
-                startedKeyguardTransitionStep,
-                finishedKeyguardState,
-        ) { startedStep, finishedState ->
-            startedStep.to == state && finishedState != state
-        }
+        return isInTransitionToStateWhere { it == state }
     }
 
     /**
@@ -251,28 +246,18 @@
      * haven't yet completed it.
      */
     fun isInTransitionToStateWhere(
-            stateMatcher: (KeyguardState) -> Boolean,
+        stateMatcher: (KeyguardState) -> Boolean,
     ): Flow<Boolean> {
-        return combine(
-                startedKeyguardTransitionStep,
-                finishedKeyguardState,
-        ) { startedStep, finishedState ->
-            stateMatcher(startedStep.to) && finishedState != startedStep.from
-        }
+        return isInTransitionWhere(fromStatePredicate = { true }, toStatePredicate = stateMatcher)
     }
 
     /**
      * Whether we're in a transition out of the given [KeyguardState], but haven't yet completed it.
      */
     fun isInTransitionFromState(
-            state: KeyguardState,
+        state: KeyguardState,
     ): Flow<Boolean> {
-        return combine(
-                startedKeyguardTransitionStep,
-                finishedKeyguardState,
-        ) { startedStep, finishedState ->
-            startedStep.from == state && finishedState != state
-        }
+        return isInTransitionFromStateWhere { it == state }
     }
 
     /**
@@ -280,14 +265,9 @@
      * haven't yet completed it.
      */
     fun isInTransitionFromStateWhere(
-            stateMatcher: (KeyguardState) -> Boolean,
+        stateMatcher: (KeyguardState) -> Boolean,
     ): Flow<Boolean> {
-        return combine(
-                startedKeyguardTransitionStep,
-                finishedKeyguardState,
-        ) { startedStep, finishedState ->
-            stateMatcher(startedStep.from) && finishedState != startedStep.from
-        }
+        return isInTransitionWhere(fromStatePredicate = stateMatcher, toStatePredicate = { true })
     }
 
     /**
@@ -299,26 +279,23 @@
         toStatePredicate: (KeyguardState) -> Boolean,
     ): Flow<Boolean> {
         return combine(
-            startedKeyguardTransitionStep,
-            finishedKeyguardState,
-        ) { startedStep, finishedState ->
-            fromStatePredicate(startedStep.from)
-                    && toStatePredicate(startedStep.to)
-                    && finishedState != startedStep.from
-        }
+                startedKeyguardTransitionStep,
+                finishedKeyguardState,
+            ) { startedStep, finishedState ->
+                fromStatePredicate(startedStep.from) &&
+                    toStatePredicate(startedStep.to) &&
+                    finishedState != startedStep.to
+            }
+            .distinctUntilChanged()
     }
 
-    /**
-     * Whether we've FINISHED a transition to a state that matches the given predicate.
-     */
+    /** Whether we've FINISHED a transition to a state that matches the given predicate. */
     fun isFinishedInStateWhere(stateMatcher: (KeyguardState) -> Boolean): Flow<Boolean> {
-        return finishedKeyguardState.map { stateMatcher(it) }
+        return finishedKeyguardState.map { stateMatcher(it) }.distinctUntilChanged()
     }
 
-    /**
-     * Whether we've FINISHED a transition to a state that matches the given predicate.
-     */
-    fun isFinishedInState(state: KeyguardState) : Flow<Boolean> {
-        return finishedKeyguardState.map { it == state }
+    /** Whether we've FINISHED a transition to a state that matches the given predicate. */
+    fun isFinishedInState(state: KeyguardState): Flow<Boolean> {
+        return finishedKeyguardState.map { it == state }.distinctUntilChanged()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
index 596a1c0..f38bb2b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
@@ -61,4 +61,5 @@
     override fun onSwipeUpOnBouncer() {}
     override fun onPrimaryBouncerUserInput() {}
     override fun onAccessibilityAction() {}
+    override fun onWalletLaunched() = Unit
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index ef1d5ac..797dec2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.biometrics.data.repository.FacePropertyRepository
 import com.android.systemui.biometrics.shared.model.LockoutMode
+import com.android.systemui.biometrics.shared.model.SensorStrength
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
@@ -33,7 +34,6 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
 import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -44,6 +44,7 @@
 import com.android.systemui.user.data.repository.UserRepository
 import com.android.systemui.util.kotlin.pairwise
 import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
@@ -56,7 +57,6 @@
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.yield
-import javax.inject.Inject
 
 /**
  * Encapsulates business logic related face authentication being triggered for device entry from
@@ -79,7 +79,6 @@
     private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
     private val userRepository: UserRepository,
     private val facePropertyRepository: FacePropertyRepository,
-    private val keyguardRepository: KeyguardRepository,
     private val faceWakeUpTriggersConfig: FaceWakeUpTriggersConfig,
     private val powerInteractor: PowerInteractor,
 ) : CoreStartable, KeyguardFaceAuthInteractor {
@@ -207,6 +206,12 @@
         runFaceAuth(FaceAuthUiEvent.FACE_AUTH_ACCESSIBILITY_ACTION, false)
     }
 
+    override fun onWalletLaunched() {
+        if (facePropertyRepository.sensorInfo.value?.strength == SensorStrength.STRONG) {
+            runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED, true)
+        }
+    }
+
     override fun registerListener(listener: FaceAuthenticationListener) {
         listeners.add(listener)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
new file mode 100644
index 0000000..41af9e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import android.view.View
+import android.view.ViewGroup
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.scrim.ScrimView
+import com.android.systemui.shade.NotificationShadeWindowView
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class AlternateBouncerBinder
+@Inject
+constructor(
+    private val notificationShadeWindowView: NotificationShadeWindowView,
+    private val featureFlags: FeatureFlagsClassic,
+    private val alternateBouncerViewModel: AlternateBouncerViewModel,
+    @Application private val scope: CoroutineScope,
+    private val notificationShadeWindowController: NotificationShadeWindowController,
+) : CoreStartable {
+    override fun start() {
+        if (!featureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+            return
+        }
+
+        AlternateBouncerViewBinder.bind(
+            notificationShadeWindowView.requireViewById(R.id.alternate_bouncer),
+            alternateBouncerViewModel,
+            scope,
+            notificationShadeWindowController,
+        )
+    }
+}
+
+/**
+ * Binds the alternate bouncer view to its view-model.
+ *
+ * To use this properly, users should maintain a one-to-one relationship between the [View] and the
+ * view-binding, binding each view only once. It is okay and expected for the same instance of the
+ * view-model to be reused for multiple view/view-binder bindings.
+ */
+@ExperimentalCoroutinesApi
+object AlternateBouncerViewBinder {
+
+    /** Binds the view to the view-model, continuing to update the former based on the latter. */
+    @JvmStatic
+    fun bind(
+        view: ViewGroup,
+        viewModel: AlternateBouncerViewModel,
+        scope: CoroutineScope,
+        notificationShadeWindowController: NotificationShadeWindowController,
+    ) {
+        scope.launch {
+            // forcePluginOpen is necessary to show over occluded apps.
+            // This cannot be tied to the view's lifecycle because setting this allows the view
+            // to be started in the first place.
+            viewModel.forcePluginOpen.collect {
+                notificationShadeWindowController.setForcePluginOpen(it, this)
+            }
+        }
+
+        val scrim = view.requireViewById(R.id.alternate_bouncer_scrim) as ScrimView
+        view.repeatWhenAttached { alternateBouncerViewContainer ->
+            repeatOnLifecycle(Lifecycle.State.STARTED) {
+                scrim.viewAlpha = 0f
+
+                launch {
+                    viewModel.onClickListener.collect {
+                        // TODO (b/287599719): Support swiping to dismiss altBouncer
+                        alternateBouncerViewContainer.setOnClickListener(it)
+                    }
+                }
+
+                launch {
+                    viewModel.scrimAlpha.collect {
+                        alternateBouncerViewContainer.visibility =
+                            if (it < .1f) View.INVISIBLE else View.VISIBLE
+                        scrim.viewAlpha = it
+                    }
+                }
+
+                launch { viewModel.scrimColor.collect { scrim.tint = it } }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index abc30ef..c5a8375 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -47,6 +47,7 @@
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.doOnEnd
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -402,6 +403,9 @@
                         KeyguardBottomAreaVibrations.ShakeAnimationDuration.inWholeMilliseconds
                     shakeAnimator.interpolator =
                         CycleInterpolator(KeyguardBottomAreaVibrations.ShakeAnimationCycles)
+                    shakeAnimator.doOnEnd {
+                        view.translationX = 0f
+                    }
                     shakeAnimator.start()
 
                     vibratorHelper?.vibrate(KeyguardBottomAreaVibrations.Shake)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
index aa76702..99025ace 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.doOnEnd
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.combine
@@ -134,7 +135,14 @@
         vibratorHelper: VibratorHelper?,
     ) {
         if (!viewModel.isVisible) {
-            view.isInvisible = true
+            view.alpha = 1f
+            view
+                    .animate()
+                    .alpha(0f)
+                    .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
+                    .setDuration(EXIT_DOZE_BUTTON_REVEAL_ANIMATION_DURATION_MS)
+                    .withEndAction { view.isInvisible = true }
+                    .start()
             return
         }
 
@@ -142,11 +150,9 @@
             view.isVisible = true
             if (viewModel.animateReveal) {
                 view.alpha = 0f
-                view.translationY = view.height / 2f
                 view
                     .animate()
                     .alpha(1f)
-                    .translationY(0f)
                     .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
                     .setDuration(EXIT_DOZE_BUTTON_REVEAL_ANIMATION_DURATION_MS)
                     .start()
@@ -235,6 +241,9 @@
                         KeyguardBottomAreaVibrations.ShakeAnimationDuration.inWholeMilliseconds
                     shakeAnimator.interpolator =
                         CycleInterpolator(KeyguardBottomAreaVibrations.ShakeAnimationCycles)
+                    shakeAnimator.doOnEnd {
+                        view.translationX = 0f
+                    }
                     shakeAnimator.start()
 
                     vibratorHelper?.vibrate(KeyguardBottomAreaVibrations.Shake)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsKeyguardViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsKeyguardViewBinder.kt
index a0e0da4..475d26f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsKeyguardViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsKeyguardViewBinder.kt
@@ -23,7 +23,6 @@
 import androidx.asynclayoutinflater.view.AsyncLayoutInflater
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.res.R
 import com.android.systemui.biometrics.UdfpsKeyguardView
 import com.android.systemui.biometrics.ui.binder.UdfpsKeyguardInternalViewBinder
 import com.android.systemui.keyguard.ui.viewmodel.BackgroundViewModel
@@ -32,6 +31,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardInternalViewModel
 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.launch
@@ -52,8 +52,6 @@
         fingerprintViewModel: FingerprintViewModel,
         backgroundViewModel: BackgroundViewModel,
     ) {
-        view.useExpandedOverlay(viewModel.useExpandedOverlay())
-
         val layoutInflaterFinishListener =
             AsyncLayoutInflater.OnInflateFinishedListener { inflatedInternalView, _, parent ->
                 UdfpsKeyguardInternalViewBinder.bind(
@@ -63,25 +61,21 @@
                     fingerprintViewModel,
                     backgroundViewModel,
                 )
-                if (viewModel.useExpandedOverlay()) {
-                    val lp = inflatedInternalView.layoutParams as FrameLayout.LayoutParams
-                    lp.width = viewModel.sensorBounds.width()
-                    lp.height = viewModel.sensorBounds.height()
-                    val relativeToView =
-                        getBoundsRelativeToView(
-                            inflatedInternalView,
-                            RectF(viewModel.sensorBounds),
-                        )
-                    lp.setMarginsRelative(
-                        relativeToView.left.toInt(),
-                        relativeToView.top.toInt(),
-                        relativeToView.right.toInt(),
-                        relativeToView.bottom.toInt(),
+                val lp = inflatedInternalView.layoutParams as FrameLayout.LayoutParams
+                lp.width = viewModel.sensorBounds.width()
+                lp.height = viewModel.sensorBounds.height()
+                val relativeToView =
+                    getBoundsRelativeToView(
+                        inflatedInternalView,
+                        RectF(viewModel.sensorBounds),
                     )
-                    parent!!.addView(inflatedInternalView, lp)
-                } else {
-                    parent!!.addView(inflatedInternalView)
-                }
+                lp.setMarginsRelative(
+                    relativeToView.left.toInt(),
+                    relativeToView.top.toInt(),
+                    relativeToView.right.toInt(),
+                    relativeToView.bottom.toInt(),
+                )
+                parent!!.addView(inflatedInternalView, lp)
             }
         val inflater = AsyncLayoutInflater(view.context)
         inflater.inflate(R.layout.udfps_keyguard_view_internal, view, layoutInflaterFinishListener)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 231eeb5..c6d8ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -22,17 +22,19 @@
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
-import android.content.res.Resources
 import android.graphics.Rect
 import android.hardware.display.DisplayManager
 import android.os.Bundle
 import android.os.Handler
 import android.os.IBinder
+import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
 import android.view.LayoutInflater
 import android.view.SurfaceControlViewHost
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD
 import android.widget.FrameLayout
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.view.isInvisible
@@ -126,6 +128,8 @@
     private val shouldHideClock: Boolean =
         bundle.getBoolean(ClockPreviewConstants.KEY_HIDE_CLOCK, false)
     private val wallpaperColors: WallpaperColors? = bundle.getParcelable(KEY_COLORS)
+    private val displayId = bundle.getInt(KEY_DISPLAY_ID, DEFAULT_DISPLAY)
+    private val display: Display = displayManager.getDisplay(displayId)
 
     private var host: SurfaceControlViewHost
 
@@ -165,7 +169,7 @@
             host =
                 SurfaceControlViewHost(
                     context,
-                    displayManager.getDisplay(bundle.getInt(KEY_DISPLAY_ID)),
+                    displayManager.getDisplay(DEFAULT_DISPLAY),
                     hostToken,
                     "KeyguardPreviewRenderer"
                 )
@@ -175,21 +179,27 @@
 
     fun render() {
         mainHandler.post {
-            val rootView = FrameLayout(context)
+            val previewContext = context.createDisplayContext(display)
 
-            setupKeyguardRootView(rootView)
+            val rootView = FrameLayout(previewContext)
+
+            setupKeyguardRootView(previewContext, rootView)
 
             if (!featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                 setUpBottomArea(rootView)
             }
 
+            val windowContext = context.createWindowContext(display, TYPE_KEYGUARD, null)
+            val windowManagerOfDisplay = windowContext.getSystemService(WindowManager::class.java)
             rootView.measure(
                 View.MeasureSpec.makeMeasureSpec(
-                    windowManager.currentWindowMetrics.bounds.width(),
+                    windowManagerOfDisplay?.currentWindowMetrics?.bounds?.width()
+                        ?: windowManager.currentWindowMetrics.bounds.width(),
                     View.MeasureSpec.EXACTLY
                 ),
                 View.MeasureSpec.makeMeasureSpec(
-                    windowManager.currentWindowMetrics.bounds.height(),
+                    windowManagerOfDisplay?.currentWindowMetrics?.bounds?.height()
+                        ?: windowManager.currentWindowMetrics.bounds.height(),
                     View.MeasureSpec.EXACTLY
                 ),
             )
@@ -252,7 +262,7 @@
      *
      * The end padding is as follows: Below clock padding end
      */
-    private fun setUpSmartspace(parentView: ViewGroup) {
+    private fun setUpSmartspace(previewContext: Context, parentView: ViewGroup) {
         if (
             !lockscreenSmartspaceController.isEnabled() ||
                 !lockscreenSmartspaceController.isDateWeatherDecoupled()
@@ -264,12 +274,12 @@
 
         val topPadding: Int =
             KeyguardPreviewSmartspaceViewModel.getLargeClockSmartspaceTopPadding(
-                context.resources,
+                previewContext.resources,
             )
         val startPadding: Int =
-            context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start)
+            previewContext.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start)
         val endPadding: Int =
-            context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end)
+            previewContext.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end)
 
         smartSpaceView?.let {
             it.setPaddingRelative(startPadding, topPadding, endPadding, 0)
@@ -309,8 +319,8 @@
     }
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    private fun setupKeyguardRootView(rootView: FrameLayout) {
-        val keyguardRootView = KeyguardRootView(context, null).apply { removeAllViews() }
+    private fun setupKeyguardRootView(previewContext: Context, rootView: FrameLayout) {
+        val keyguardRootView = KeyguardRootView(previewContext, null).apply { removeAllViews() }
         disposables.add(
             KeyguardRootViewBinder.bind(
                 keyguardRootView,
@@ -334,10 +344,10 @@
             if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                 setupShortcuts(keyguardRootView)
             }
-            setUpUdfps(rootView)
+            setUpUdfps(previewContext, rootView)
 
             if (!shouldHideClock) {
-                setUpClock(rootView)
+                setUpClock(previewContext, rootView)
                 KeyguardPreviewClockViewBinder.bind(
                     largeClockHostView,
                     smallClockHostView,
@@ -345,7 +355,7 @@
                 )
             }
 
-            setUpSmartspace(rootView)
+            setUpSmartspace(previewContext, rootView)
             smartSpaceView?.let {
                 KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel)
             }
@@ -382,7 +392,7 @@
         }
     }
 
-    private fun setUpUdfps(parentView: ViewGroup) {
+    private fun setUpUdfps(previewContext: Context, parentView: ViewGroup) {
         val sensorBounds = udfpsOverlayInteractor.udfpsOverlayParams.value.sensorBounds
 
         // If sensorBounds are default rect, then there is no UDFPS
@@ -400,7 +410,7 @@
             sensorBounds.bottom
         )
         val finger =
-            LayoutInflater.from(context)
+            LayoutInflater.from(previewContext)
                 .inflate(
                     R.layout.udfps_keyguard_preview,
                     parentView,
@@ -409,17 +419,54 @@
         parentView.addView(finger, fingerprintLayoutParams)
     }
 
-    private fun setUpClock(parentView: ViewGroup) {
+    private fun setUpClock(previewContext: Context, parentView: ViewGroup) {
         largeClockHostView =
-            if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW))
+            if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
                 parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view_large)
-            else createLargeClockHostView()
+            } else {
+                val hostView = FrameLayout(previewContext)
+                hostView.layoutParams =
+                    FrameLayout.LayoutParams(
+                        FrameLayout.LayoutParams.MATCH_PARENT,
+                        FrameLayout.LayoutParams.MATCH_PARENT,
+                    )
+                parentView.addView(hostView)
+                hostView
+            }
         largeClockHostView.isInvisible = true
 
         smallClockHostView =
-            if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW))
+            if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
                 parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view)
-            else createSmallClockHostView(parentView.resources)
+            } else {
+                val resources = parentView.resources
+                val hostView = FrameLayout(previewContext)
+                val layoutParams =
+                    FrameLayout.LayoutParams(
+                        FrameLayout.LayoutParams.WRAP_CONTENT,
+                        resources.getDimensionPixelSize(
+                            com.android.systemui.customization.R.dimen.small_clock_height
+                        )
+                    )
+                layoutParams.topMargin =
+                    KeyguardPreviewSmartspaceViewModel.getStatusBarHeight(resources) +
+                        resources.getDimensionPixelSize(
+                            com.android.systemui.customization.R.dimen.small_clock_padding_top
+                        )
+                hostView.layoutParams = layoutParams
+
+                hostView.setPaddingRelative(
+                    resources.getDimensionPixelSize(
+                        com.android.systemui.customization.R.dimen.clock_padding_start
+                    ),
+                    0,
+                    0,
+                    0
+                )
+                hostView.clipChildren = false
+                parentView.addView(hostView)
+                hostView
+            }
         smallClockHostView.isInvisible = true
 
         // TODO (b/283465254): Move the listeners to KeyguardClockRepository
@@ -476,44 +523,6 @@
         onClockChanged()
     }
 
-    private fun createLargeClockHostView(): FrameLayout {
-        val hostView = FrameLayout(context)
-        hostView.layoutParams =
-            FrameLayout.LayoutParams(
-                FrameLayout.LayoutParams.MATCH_PARENT,
-                FrameLayout.LayoutParams.MATCH_PARENT,
-            )
-        return hostView
-    }
-
-    private fun createSmallClockHostView(resources: Resources): FrameLayout {
-        val hostView = FrameLayout(context)
-        val layoutParams =
-            FrameLayout.LayoutParams(
-                FrameLayout.LayoutParams.WRAP_CONTENT,
-                resources.getDimensionPixelSize(
-                    com.android.systemui.customization.R.dimen.small_clock_height
-                )
-            )
-        layoutParams.topMargin =
-            KeyguardPreviewSmartspaceViewModel.getStatusBarHeight(resources) +
-                resources.getDimensionPixelSize(
-                    com.android.systemui.customization.R.dimen.small_clock_padding_top
-                )
-        hostView.layoutParams = layoutParams
-
-        hostView.setPaddingRelative(
-            resources.getDimensionPixelSize(
-                com.android.systemui.customization.R.dimen.clock_padding_start
-            ),
-            0,
-            0,
-            0
-        )
-        hostView.clipChildren = false
-        return hostView
-    }
-
     private fun onClockChanged() {
         val clock = clockRegistry.createCurrentClock()
         clockController.clock = clock
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
index e8df1a6..d8e4396 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.keyguard.ui.view.layout.blueprints
 
+import com.android.systemui.communal.ui.view.layout.sections.CommunalTutorialIndicatorSection
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
@@ -53,6 +54,7 @@
     splitShadeGuidelines: SplitShadeGuidelines,
     aodNotificationIconsSection: AodNotificationIconsSection,
     aodBurnInSection: AodBurnInSection,
+    communalTutorialIndicatorSection: CommunalTutorialIndicatorSection,
 ) : KeyguardBlueprint {
     override val id: String = DEFAULT
 
@@ -69,6 +71,7 @@
             splitShadeGuidelines,
             aodNotificationIconsSection,
             aodBurnInSection,
+            communalTutorialIndicatorSection,
         )
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
index 1a9f021..0b0f21d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -31,12 +31,12 @@
 import androidx.constraintlayout.widget.ConstraintSet.TOP
 import com.android.keyguard.KeyguardStatusView
 import com.android.keyguard.dagger.KeyguardStatusViewComponent
-import com.android.systemui.res.R
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.KeyguardViewConfigurator
 import com.android.systemui.keyguard.shared.model.KeyguardSection
 import com.android.systemui.media.controls.ui.KeyguardMediaController
+import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationPanelView
 import com.android.systemui.shade.NotificationPanelViewController
 import com.android.systemui.statusbar.policy.SplitShadeStateController
@@ -84,7 +84,8 @@
     override fun bindData(constraintLayout: ConstraintLayout) {
         if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
             constraintLayout.findViewById<KeyguardStatusView?>(R.id.keyguard_status_view)?.let {
-                val statusViewComponent = keyguardStatusViewComponentFactory.build(it)
+                val statusViewComponent =
+                    keyguardStatusViewComponentFactory.build(it, context.display)
                 val controller = statusViewComponent.keyguardStatusViewController
                 controller.init()
                 keyguardMediaController.attachSplitShadeContainer(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
new file mode 100644
index 0000000..235a28d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import android.graphics.Color
+import android.view.View
+import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TRANSITION_DURATION_MS
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.wm.shell.animation.Interpolators
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+@ExperimentalCoroutinesApi
+class AlternateBouncerViewModel
+@Inject
+constructor(
+    statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+    transitionInteractor: KeyguardTransitionInteractor,
+    falsingManager: FalsingManager,
+) {
+    // When we're fully transitioned to the AlternateBouncer, the alpha of the scrim should be:
+    private val alternateBouncerScrimAlpha = .66f
+    private val toAlternateBouncerTransition =
+        KeyguardTransitionAnimationFlow(
+                transitionDuration = TRANSITION_DURATION_MS,
+                transitionFlow = transitionInteractor.anyStateToAlternateBouncerTransition,
+            )
+            .createFlow(
+                duration = TRANSITION_DURATION_MS,
+                onStep = { it },
+                onFinish = { 1f },
+                // Reset on cancel
+                onCancel = { 0f },
+                interpolator = Interpolators.FAST_OUT_SLOW_IN,
+            )
+    private val fromAlternateBouncerTransition =
+        KeyguardTransitionAnimationFlow(
+                transitionDuration = TRANSITION_DURATION_MS,
+                transitionFlow = transitionInteractor.transitionStepsFromState(ALTERNATE_BOUNCER),
+            )
+            .createFlow(
+                duration = TRANSITION_DURATION_MS,
+                onStep = { 1f - it },
+                // Reset on cancel
+                onCancel = { 0f },
+                interpolator = Interpolators.FAST_OUT_SLOW_IN,
+            )
+
+    /** Progress to a fully transitioned alternate bouncer. 1f represents fully transitioned. */
+    private val transitionToAlternateBouncerProgress =
+        merge(fromAlternateBouncerTransition, toAlternateBouncerTransition)
+
+    val forcePluginOpen: Flow<Boolean> =
+        transitionToAlternateBouncerProgress.map { it > 0f }.distinctUntilChanged()
+
+    /** An observable for the scrim alpha. */
+    val scrimAlpha = transitionToAlternateBouncerProgress.map { it * alternateBouncerScrimAlpha }
+
+    /** An observable for the scrim color. Change color for easier debugging. */
+    val scrimColor: Flow<Int> = flowOf(Color.BLACK)
+
+    private val clickListener =
+        View.OnClickListener {
+            if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+                statusBarKeyguardViewManager.showPrimaryBouncer(/* scrimmed */ true)
+            }
+        }
+
+    val onClickListener: Flow<View.OnClickListener?> =
+        transitionToAlternateBouncerProgress
+            .map {
+                if (it == 1f) {
+                    clickListener
+                } else {
+                    null
+                }
+            }
+            .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsKeyguardViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsKeyguardViewModel.kt
index 929f27f..dca151d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsKeyguardViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsKeyguardViewModel.kt
@@ -17,20 +17,10 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import android.graphics.Rect
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
 @ExperimentalCoroutinesApi
-class UdfpsKeyguardViewModel
-@Inject
-constructor(
-    private val featureFlags: FeatureFlags,
-) {
+class UdfpsKeyguardViewModel @Inject constructor() {
     var sensorBounds: Rect = Rect()
-
-    fun useExpandedOverlay(): Boolean {
-        return featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
index 54abc5b..0b1079f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt
@@ -19,13 +19,13 @@
 import android.content.Context
 import androidx.annotation.ColorInt
 import com.android.settingslib.Utils.getColorAttrDefaultColor
-import com.android.systemui.res.R
 import com.android.systemui.keyguard.domain.interactor.BurnInOffsets
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.res.R
 import com.android.wm.shell.animation.Interpolators
 import javax.inject.Inject
 import kotlin.math.roundToInt
@@ -62,7 +62,7 @@
 
     private val toAlternateBouncer: Flow<TransitionViewModel> =
         keyguardInteractor.statusBarState.flatMapLatest { statusBarState ->
-            transitionInteractor.anyStateToAlternateBouncerTransition.map {
+            transitionInteractor.transitionStepsToState(KeyguardState.ALTERNATE_BOUNCER).map {
                 TransitionViewModel(
                     alpha = 1f,
                     scale =
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 1943b34..67531ad 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -30,6 +30,8 @@
 import com.android.systemui.log.table.TableLogBuffer;
 import com.android.systemui.log.table.TableLogBufferFactory;
 import com.android.systemui.qs.QSFragmentLegacy;
+import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository;
+import com.android.systemui.qs.pipeline.shared.TileSpec;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.util.Compile;
 import com.android.systemui.util.wakelock.WakeLockLog;
@@ -37,6 +39,9 @@
 import dagger.Module;
 import dagger.Provides;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Dagger module for providing instances of {@link LogBuffer}.
  */
@@ -173,8 +178,35 @@
     @Provides
     @SysUISingleton
     @QSLog
-    public static LogBuffer provideQuickSettingsLogBuffer(LogBufferFactory factory) {
-        return factory.create("QSLog", 700 /* maxSize */, false /* systrace */);
+    public static LogBuffer provideQuickSettingsLogBuffer(
+            LogBufferFactory factory,
+            QSPipelineFlagsRepository flags
+    ) {
+        if (flags.getPipelineTilesEnabled()) {
+            // we use
+            return factory.create("QSLog", 450 /* maxSize */, false /* systrace */);
+        } else {
+            return factory.create("QSLog", 700 /* maxSize */, false /* systrace */);
+        }
+    }
+
+    /**
+     * Provides a logging buffer for all logs related to Quick Settings tiles. This LogBuffer is
+     * unique for each tile.
+     * go/qs-tile-refactor
+     */
+    @Provides
+    @QSTilesDefaultLog
+    public static LogBuffer provideQuickSettingsTilesLogBuffer(LogBufferFactory factory) {
+        return factory.create("QSTileLog", 25 /* maxSize */, false /* systrace */);
+    }
+
+    @Provides
+    @QSTilesLogBuffers
+    public static Map<TileSpec, LogBuffer> provideQuickSettingsTilesLogBufferCache() {
+        final Map<TileSpec, LogBuffer> buffers = new HashMap<>();
+        // Add chatty buffers here
+        return buffers;
     }
 
     /** Provides a logging buffer for logs related to Quick Settings configuration. */
@@ -420,7 +452,7 @@
 
     /**
      * Provides a {@link LogBuffer} for use by
-     *  {@link com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepositoryImpl}.
+     * {@link com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepositoryImpl}.
      */
     @Provides
     @SysUISingleton
@@ -431,7 +463,7 @@
 
     /**
      * Provides a {@link LogBuffer} for use by classes in the
-     *  {@link com.android.systemui.keyguard.bouncer} package.
+     * {@link com.android.systemui.keyguard.bouncer} package.
      */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesDefaultLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesDefaultLog.kt
new file mode 100644
index 0000000..6575cdd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesDefaultLog.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 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.log.dagger
+
+import javax.inject.Qualifier
+
+/**
+ * A default [com.android.systemui.log.LogBuffer] for QS tiles messages. It's used exclusively in
+ * [com.android.systemui.qs.tiles.base.logging.QSTileLogger]. If you need to increase it for you
+ * tile, add one to the map provided by the [QSTilesLogBuffers]
+ */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class QSTilesDefaultLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesLogBuffers.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesLogBuffers.kt
new file mode 100644
index 0000000..62d49fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesLogBuffers.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.log.dagger
+
+import javax.inject.Qualifier
+
+/**
+ * Provides a map with custom [com.android.systemui.log.LogBuffer] for QS tiles messages. Add
+ * buffers to it when the tile needs to be more verbose and the default buffer provided by
+ * [QSTilesDefaultLog] is not enough.
+ *
+ * This is not a multibinding. Add new logs directly to [LogModule]
+ */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class QSTilesLogBuffers
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesVerboseLog.java
similarity index 60%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java
copy to packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesVerboseLog.java
index 3fff136..b0c2f8c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSTilesVerboseLog.java
@@ -14,18 +14,23 @@
  * limitations under the License.
  */
 
-package com.android.systemui;
+package com.android.systemui.log.dagger;
 
-import java.lang.annotation.ElementType;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
 
 /**
- * Mark as tests for Robolectric pilot projects. The filter can better help grouping test results
- * that runs on CI
+ * A {@link LogBuffer} for QS tiles messages. It's used exclusively in
+ * {@link com.android.systemui.qs.tiles.base.logging.QSTileLogger}
  */
-@Target({ElementType.METHOD, ElementType.TYPE})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface RoboPilotTest {
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface QSTilesVerboseLog {
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 3d4fca1..1b3b473 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -51,11 +51,12 @@
         Uri uri;
         boolean looping;
         AudioAttributes attributes;
+        float volume;
         long requestTime;
 
         public String toString() {
             return "{ code=" + code + " looping=" + looping + " attributes=" + attributes
-                    + " uri=" + uri + " }";
+                    + " volume=" + volume + " uri=" + uri + " }";
         }
     }
 
@@ -101,6 +102,7 @@
                     player.setAudioAttributes(mCmd.attributes);
                     player.setDataSource(mCmd.context, mCmd.uri);
                     player.setLooping(mCmd.looping);
+                    player.setVolume(mCmd.volume);
                     player.setOnCompletionListener(NotificationPlayer.this);
                     player.setOnErrorListener(NotificationPlayer.this);
                     player.prepare();
@@ -401,10 +403,11 @@
      *          (see {@link MediaPlayer#setLooping(boolean)})
      * @param stream the AudioStream to use.
      *          (see {@link MediaPlayer#setAudioStreamType(int)})
+     * @param volume the volume for the audio with values in range [0.0, 1.0]
      * @deprecated use {@link #play(Context, Uri, boolean, AudioAttributes)} instead.
      */
     @Deprecated
-    public void play(Context context, Uri uri, boolean looping, int stream) {
+    public void play(Context context, Uri uri, boolean looping, int stream, float volume) {
         if (DEBUG) { Log.d(mTag, "play uri=" + uri.toString()); }
         PlayerBase.deprecateStreamTypeForPlayback(stream, "NotificationPlayer", "play");
         Command cmd = new Command();
@@ -414,6 +417,7 @@
         cmd.uri = uri;
         cmd.looping = looping;
         cmd.attributes = new AudioAttributes.Builder().setInternalLegacyStreamType(stream).build();
+        cmd.volume = volume;
         synchronized (mCmdQueue) {
             enqueueLocked(cmd);
             mState = PLAY;
@@ -432,8 +436,10 @@
      *          (see {@link MediaPlayer#setLooping(boolean)})
      * @param attributes the AudioAttributes to use.
      *          (see {@link MediaPlayer#setAudioAttributes(AudioAttributes)})
+     * @param volume the volume for the audio with values in range [0.0, 1.0]
      */
-    public void play(Context context, Uri uri, boolean looping, AudioAttributes attributes) {
+    public void play(Context context, Uri uri, boolean looping, AudioAttributes attributes,
+            float volume) {
         if (DEBUG) { Log.d(mTag, "play uri=" + uri.toString()); }
         Command cmd = new Command();
         cmd.requestTime = SystemClock.uptimeMillis();
@@ -442,6 +448,7 @@
         cmd.uri = uri;
         cmd.looping = looping;
         cmd.attributes = attributes;
+        cmd.volume = volume;
         synchronized (mCmdQueue) {
             enqueueLocked(cmd);
             mState = PLAY;
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 68202d5..7a48836 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -38,6 +38,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.VibrationEffect;
+import android.os.vibrator.Flags;
 import android.provider.MediaStore;
 import android.util.Log;
 
@@ -111,7 +112,7 @@
         @Override
         public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping)
                 throws RemoteException {
-            if (Ringtone.useRingtoneV2()) {
+            if (Flags.hapticsCustomizationRingtoneV2Enabled()) {
                 playRemoteRingtone(token, uri, aa, true, Ringtone.MEDIA_SOUND,
                         null, volume, looping, /* hapticGenerator= */ false,
                         null);
@@ -284,7 +285,8 @@
         }
 
         @Override
-        public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa) {
+        public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa,
+                float volume) {
             if (LOGD) Log.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Async playback only available from system UID.");
@@ -292,7 +294,7 @@
             if (UserHandle.ALL.equals(user)) {
                 user = UserHandle.SYSTEM;
             }
-            mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);
+            mAsyncPlayer.play(getContextForUser(user), uri, looping, aa, volume);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 0f3e0ac..2a32ddf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -60,7 +60,6 @@
 import com.android.internal.logging.InstanceId
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.Dumpable
-import com.android.systemui.res.R
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -83,6 +82,7 @@
 import com.android.systemui.media.controls.util.MediaUiEventLogger
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
 import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
 import com.android.systemui.statusbar.notification.row.HybridGroupManager
@@ -90,6 +90,7 @@
 import com.android.systemui.util.Assert
 import com.android.systemui.util.Utils
 import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.ThreadFactory
 import com.android.systemui.util.time.SystemClock
 import com.android.systemui.util.traceSection
 import java.io.IOException
@@ -245,7 +246,7 @@
     @Inject
     constructor(
         context: Context,
-        @Background backgroundExecutor: Executor,
+        threadFactory: ThreadFactory,
         @Main uiExecutor: Executor,
         @Main foregroundExecutor: DelayableExecutor,
         mediaControllerFactory: MediaControllerFactory,
@@ -267,7 +268,9 @@
         keyguardUpdateMonitor: KeyguardUpdateMonitor,
     ) : this(
         context,
-        backgroundExecutor,
+        // Loading bitmap for UMO background can take longer time, so it cannot run on the default
+        // background thread. Use a custom thread for media.
+        threadFactory.buildExecutorOnNewThread(TAG),
         uiExecutor,
         foregroundExecutor,
         mediaControllerFactory,
@@ -1429,8 +1432,6 @@
     }
 
     private fun onSessionDestroyed(key: String) {
-        if (!mediaFlags.isRetainingPlayersEnabled()) return
-
         if (DEBUG) Log.d(TAG, "session destroyed for $key")
         val entry = mediaEntries.remove(key) ?: return
         // Clear token since the session is no longer valid
@@ -1474,7 +1475,7 @@
             if (DEBUG) Log.d(TAG, "Removing still-active player $key")
             notifyMediaDataRemoved(key)
             logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
-        } else {
+        } else if (mediaFlags.isRetainingPlayersEnabled() || isAbleToResume(removed)) {
             // Convert to resume
             if (DEBUG) {
                 Log.d(
@@ -1484,6 +1485,11 @@
                 )
             }
             convertToResumePlayer(key, removed)
+        } else {
+            // Retaining players flag is off and app doesn't support resume: remove player.
+            if (DEBUG) Log.d(TAG, "Removing player $key")
+            notifyMediaDataRemoved(key)
+            logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
index 72aea04..2217509 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -33,6 +33,8 @@
 import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider
 import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController
 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider
+import com.android.systemui.mediaprojection.appselector.view.WindowMetricsProvider
+import com.android.systemui.mediaprojection.appselector.view.WindowMetricsProviderImpl
 import com.android.systemui.mediaprojection.devicepolicy.MediaProjectionDevicePolicyModule
 import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile
 import com.android.systemui.mediaprojection.permission.MediaProjectionPermissionActivity
@@ -106,6 +108,8 @@
         impl: TaskPreviewSizeProvider
     ): DefaultLifecycleObserver
 
+    @Binds fun windowMetricsProvider(impl: WindowMetricsProviderImpl): WindowMetricsProvider
+
     companion object {
         @Provides
         @MediaProjectionAppSelector
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt
index 864d35a..c829471 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt
@@ -19,8 +19,6 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.graphics.Rect
-import android.view.WindowInsets.Type
-import android.view.WindowManager
 import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.LifecycleOwner
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope
@@ -36,7 +34,7 @@
 @Inject
 constructor(
     private val context: Context,
-    private val windowManager: WindowManager,
+    private val windowMetricsProvider: WindowMetricsProvider,
     private val configurationController: ConfigurationController,
 ) : CallbackController<TaskPreviewSizeListener>, ConfigurationListener, DefaultLifecycleObserver {
 
@@ -62,17 +60,14 @@
     }
 
     private fun calculateSize(): Rect {
-        val windowMetrics = windowManager.maximumWindowMetrics
-        val maximumWindowHeight = windowMetrics.bounds.height()
-        val width = windowMetrics.bounds.width()
+        val maxWindowBounds = windowMetricsProvider.maximumWindowBounds
+        val maximumWindowHeight = maxWindowBounds.height()
+        val width = maxWindowBounds.width()
         var height = maximumWindowHeight
 
         val isLargeScreen = isLargeScreen(context)
         if (isLargeScreen) {
-            val taskbarSize =
-                windowManager.currentWindowMetrics.windowInsets
-                    .getInsets(Type.tappableElement())
-                    .bottom
+            val taskbarSize = windowMetricsProvider.currentWindowInsets.bottom
             height -= taskbarSize
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProvider.kt
new file mode 100644
index 0000000..1932920
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProvider.kt
@@ -0,0 +1,30 @@
+package com.android.systemui.mediaprojection.appselector.view
+
+import android.graphics.Insets
+import android.graphics.Rect
+import android.view.WindowInsets
+import android.view.WindowManager
+import javax.inject.Inject
+
+/** Provides values related to window metrics. */
+interface WindowMetricsProvider {
+
+    val maximumWindowBounds: Rect
+
+    val currentWindowInsets: Insets
+}
+
+class WindowMetricsProviderImpl
+@Inject
+constructor(
+    private val windowManager: WindowManager,
+) : WindowMetricsProvider {
+    override val maximumWindowBounds: Rect
+        get() = windowManager.maximumWindowMetrics.bounds
+
+    override val currentWindowInsets: Insets
+        get() =
+            windowManager.currentWindowMetrics.windowInsets.getInsets(
+                WindowInsets.Type.tappableElement()
+            )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 2b56d0c..d08d040 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -239,6 +239,8 @@
     protected void onDestroy() {
         super.onDestroy();
         if (mDialog != null) {
+            mDialog.setOnDismissListener(null);
+            mDialog.setOnCancelListener(null);
             mDialog.dismiss();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
index 07846b5..3cdcb2c 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
@@ -24,6 +24,8 @@
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.shared.system.QuickStepContract;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -108,6 +110,7 @@
         }
     }
 
+    @NeverCompile
     @Override
     public void dump(PrintWriter pw, String[] args) {
         pw.println("SysUiState state:");
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index 564e984..2928cce 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -65,6 +65,8 @@
 import com.android.wm.shell.back.BackAnimation;
 import com.android.wm.shell.pip.Pip;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import java.io.PrintWriter;
 import java.util.Optional;
 
@@ -476,6 +478,7 @@
         return mNavigationBars.get(mDisplayTracker.getDefaultDisplayId());
     }
 
+    @NeverCompile
     @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("mIsLargeScreen=" + mIsLargeScreen);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 4d6d95a..bc4f7f25 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -584,7 +584,6 @@
         if (!visible) {
             mTransitionListener.onBackAltCleared();
         }
-        mRotationButtonController.getRotationButton().setCanShowRotationButton(!visible);
     }
 
     void setDisabledFlags(int disabledFlags, SysUiState sysUiState) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 19012e2..fa18b35b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -27,11 +27,11 @@
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSPanelControllerBase.TileRecord;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.res.R;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -562,6 +562,12 @@
         if (shouldNotRunAnimation(tilesToReveal)) {
             return;
         }
+        // This method has side effects (beings the fake drag, if it returns true). If we have
+        // decided that we want to do a tile reveal, we do a last check to verify that we can
+        // actually perform a fake drag.
+        if (!beginFakeDrag()) {
+            return;
+        }
 
         final int lastPageNumber = mPages.size() - 1;
         final TileLayout lastPage = mPages.get(lastPageNumber);
@@ -596,8 +602,10 @@
     }
 
     private boolean shouldNotRunAnimation(Set<String> tilesToReveal) {
+        // None of these have side effects. That way, we don't need to rely on short-circuiting
+        // behavior
         boolean noAnimationNeeded = tilesToReveal.isEmpty() || mPages.size() < 2;
-        boolean scrollingInProgress = getScrollX() != 0 || !beginFakeDrag();
+        boolean scrollingInProgress = getScrollX() != 0 || !isFakeDragging();
         // checking mRunningInTestHarness to disable animation in functional testing as it caused
         // flakiness and is not needed there. Alternative solutions were more complex and would
         // still be either potentially flaky or modify internal data.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
index 8589ae9..68bf88b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
@@ -72,7 +72,7 @@
 
     @Override
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
-        QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(this);
+        QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(getView());
         mQsImpl = mQsImplProvider.get();
         mQsImpl.onComponentCreated(qsFragmentComponent, savedInstanceState);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
index 2a36fdb..65a2c8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
@@ -105,7 +105,7 @@
 
     override fun removeCallback(callback: QSHost.Callback) {
         if (useNewHost) {
-            synchronized(callbacksMap) { callbacksMap.get(callback)?.cancel() }
+            synchronized(callbacksMap) { callbacksMap.remove(callback)?.cancel() }
         } else {
             qsTileHost.removeCallback(callback)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index a32a024..4aad6a0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
@@ -72,6 +72,8 @@
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.util.Utils;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.function.Consumer;
@@ -199,11 +201,13 @@
         mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner();
     }
 
+    /**
+     * This method will set up all the necessary fields. Methods from the implemented interfaces
+     * should not be called before this method returns.
+     */
     public void onComponentCreated(QSComponent qsComponent, @Nullable Bundle savedInstanceState) {
         mRootView = qsComponent.getRootView();
 
-        mCommandQueue.addCallback(this);
-
         mQSPanelController = qsComponent.getQSPanelController();
         mQuickQSPanelController = qsComponent.getQuickQSPanelController();
 
@@ -270,6 +274,9 @@
                     mQSPanelController.getMediaHost().getHostView().setAlpha(1.0f);
                     mQSAnimator.requestAnimatorUpdate();
                 });
+
+        // This will immediately call disable, so it needs to be added after setting up the fields.
+        mCommandQueue.addCallback(this);
     }
 
     private void bindFooterActionsView(View root) {
@@ -323,6 +330,8 @@
     public void onDestroy() {
         mCommandQueue.removeCallback(this);
         mStatusBarStateController.removeCallback(this);
+        mQSPanelController.destroy();
+        mQuickQSPanelController.destroy();
         if (mListening) {
             setListening(false);
         }
@@ -927,6 +936,7 @@
         return mListeningAndVisibilityLifecycleOwner;
     }
 
+    @NeverCompile
     @Override
     public void dump(PrintWriter pw, String[] args) {
         IndentingPrintWriter indentingPw = new IndentingPrintWriter(pw, /* singleIndent= */ "  ");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 60c92c0..fc2f5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -158,6 +158,7 @@
     protected void onInit() {
         mView.initialize(mQSLogger);
         mQSLogger.logAllTilesChangeListening(mView.isListening(), mView.getDumpableTag(), "");
+        mHost.addCallback(mQSHostCallback);
     }
 
     /**
@@ -172,6 +173,18 @@
     }
 
     @Override
+    public void destroy() {
+        super.destroy();
+        mHost.removeCallback(mQSHostCallback);
+
+        for (TileRecord record : mRecords) {
+            record.tile.removeCallback(record.callback);
+            mView.removeTile(record);
+        }
+        mRecords.clear();
+    }
+
+    @Override
     protected void onViewAttached() {
         mQsTileRevealController = createTileRevealController();
         if (mQsTileRevealController != null) {
@@ -180,7 +193,6 @@
 
         mMediaHost.addVisibilityChangeListener(mMediaHostVisibilityListener);
         mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
-        mHost.addCallback(mQSHostCallback);
         setTiles();
         mLastOrientation = getResources().getConfiguration().orientation;
         mQSLogger.logOnViewAttached(mLastOrientation, mView.getDumpableTag());
@@ -193,16 +205,11 @@
     protected void onViewDetached() {
         mQSLogger.logOnViewDetached(mLastOrientation, mView.getDumpableTag());
         mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
-        mHost.removeCallback(mQSHostCallback);
 
         mView.getTileLayout().setListening(false, mUiEventLogger);
 
         mMediaHost.removeVisibilityChangeListener(mMediaHostVisibilityListener);
 
-        for (TileRecord record : mRecords) {
-            record.tile.removeCallback(record.callback);
-        }
-        mRecords.clear();
         mDumpManager.unregisterDumpable(mView.getDumpableTag());
     }
 
@@ -222,15 +229,30 @@
         if (!collapsedView && mQsTileRevealController != null) {
             mQsTileRevealController.updateRevealedTiles(tiles);
         }
-
-        for (QSPanelControllerBase.TileRecord record : mRecords) {
-            mView.removeTile(record);
-            record.tile.removeCallback(record.callback);
+        boolean shouldChange = false;
+        if (tiles.size() == mRecords.size()) {
+            int i = 0;
+            for (QSTile tile : tiles) {
+                if (tile != mRecords.get(i).tile) {
+                    shouldChange = true;
+                    break;
+                }
+                i++;
+            }
+        } else {
+            shouldChange = true;
         }
-        mRecords.clear();
-        mCachedSpecs = "";
-        for (QSTile tile : tiles) {
-            addTile(tile, collapsedView);
+
+        if (shouldChange) {
+            for (QSPanelControllerBase.TileRecord record : mRecords) {
+                mView.removeTile(record);
+                record.tile.removeCallback(record.callback);
+            }
+            mRecords.clear();
+            mCachedSpecs = "";
+            for (QSTile tile : tiles) {
+                addTile(tile, collapsedView);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java b/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
index 7794fa0..eb11568 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
@@ -20,15 +20,14 @@
 import android.os.Handler;
 
 import com.android.systemui.statusbar.policy.Listenable;
-import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.util.settings.SettingsProxy;
 import com.android.systemui.util.settings.SystemSettings;
 
 /**
- * Helper for managing secure, global, and system settings through use of {@link SettingsProxy},
- * which is the common superclass of {@link SecureSettings}, {@link GlobalSettings}, and
- * {@link SystemSettings}.
+ * Helper for managing global settings through use of {@link SettingsProxy}. This should
+ * <em>not</em> be used for {@link SecureSettings} or {@link SystemSettings} since those must be
+ * user-aware (instead, use {@link UserSettingObserver}).
  */
 public abstract class SettingObserver extends ContentObserver implements Listenable {
     private final SettingsProxy mSettingsProxy;
@@ -36,23 +35,20 @@
     private final int mDefaultValue;
 
     private boolean mListening;
-    private int mUserId;
     private int mObservedValue;
 
     protected abstract void handleValueChanged(int value, boolean observedChange);
 
-    public SettingObserver(SettingsProxy settingsProxy, Handler handler, String settingName,
-            int userId) {
-        this(settingsProxy, handler, settingName, userId, 0);
+    public SettingObserver(SettingsProxy settingsProxy, Handler handler, String settingName) {
+        this(settingsProxy, handler, settingName, 0);
     }
 
     public SettingObserver(SettingsProxy settingsProxy, Handler handler, String settingName,
-            int userId, int defaultValue) {
+            int defaultValue) {
         super(handler);
         mSettingsProxy = settingsProxy;
         mSettingName = settingName;
         mObservedValue = mDefaultValue = defaultValue;
-        mUserId = userId;
     }
 
     public int getValue() {
@@ -65,11 +61,11 @@
      * @param value The new value for the setting.
      */
     public void setValue(int value) {
-        mSettingsProxy.putIntForUser(mSettingName, value, mUserId);
+        mSettingsProxy.putInt(mSettingName, value);
     }
 
     private int getValueFromProvider() {
-        return mSettingsProxy.getIntForUser(mSettingName, mDefaultValue, mUserId);
+        return mSettingsProxy.getInt(mSettingName, mDefaultValue);
     }
 
     @Override
@@ -78,8 +74,8 @@
         mListening = listening;
         if (listening) {
             mObservedValue = getValueFromProvider();
-            mSettingsProxy.registerContentObserverForUser(
-                    mSettingsProxy.getUriFor(mSettingName), false, this, mUserId);
+            mSettingsProxy.registerContentObserver(
+                    mSettingsProxy.getUriFor(mSettingName), false, this);
         } else {
             mSettingsProxy.unregisterContentObserver(this);
             mObservedValue = mDefaultValue;
@@ -94,21 +90,6 @@
         handleValueChanged(value, changed);
     }
 
-    /**
-     * Set user handle for which to observe the setting.
-     */
-    public void setUserId(int userId) {
-        mUserId = userId;
-        if (mListening) {
-            setListening(false);
-            setListening(true);
-        }
-    }
-
-    public int getCurrentUser() {
-        return mUserId;
-    }
-
     public String getKey() {
         return mSettingName;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
index 11759f7..777faea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
@@ -19,7 +19,7 @@
 import android.content.Context
 import android.util.AttributeSet
 import com.android.systemui.flags.Flags
-import com.android.systemui.flags.ViewRefactorFlag
+import com.android.systemui.flags.RefactorFlag
 import com.android.systemui.res.R
 
 open class SideLabelTileLayout(
@@ -27,8 +27,8 @@
     attrs: AttributeSet?
 ) : TileLayout(context, attrs) {
 
-    private final val isSmallLandscapeLockscreenEnabled =
-            ViewRefactorFlag(flag = Flags.LOCKSCREEN_ENABLE_LANDSCAPE).isEnabled
+    private val isSmallLandscapeLockscreenEnabled =
+            RefactorFlag.forView(Flags.LOCKSCREEN_ENABLE_LANDSCAPE).isEnabled
 
     override fun updateResources(): Boolean {
         return super.updateResources().also {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 9ba1645..9d4eba5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -15,13 +15,13 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.FontSizeUtils;
-import com.android.systemui.flags.ViewRefactorFlag;
-import com.android.systemui.res.R;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSPanelControllerBase.TileRecord;
 import com.android.systemui.qs.tileimpl.HeightOverrideable;
 import com.android.systemui.qs.tileimpl.QSTileViewImplKt;
+import com.android.systemui.res.R;
 
 import java.util.ArrayList;
 
@@ -55,7 +55,7 @@
     protected int mLastTileBottom;
     protected TextView mTempTextView;
     private final Boolean mIsSmallLandscapeLockscreenEnabled =
-            new ViewRefactorFlag(Flags.LOCKSCREEN_ENABLE_LANDSCAPE).isEnabled();
+            RefactorFlag.forView(Flags.LOCKSCREEN_ENABLE_LANDSCAPE).isEnabled();
 
     public TileLayout(Context context) {
         this(context, null);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/UserSettingObserver.java b/packages/SystemUI/src/com/android/systemui/qs/UserSettingObserver.java
new file mode 100644
index 0000000..539c2d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/UserSettingObserver.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2023 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.database.ContentObserver;
+import android.os.Handler;
+
+import com.android.systemui.statusbar.policy.Listenable;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.settings.SystemSettings;
+import com.android.systemui.util.settings.UserSettingsProxy;
+
+/**
+ * Helper for managing secure and system settings through use of {@link UserSettingsProxy},
+ * which is the common superclass of {@link SecureSettings} and {@link SystemSettings}.
+ */
+public abstract class UserSettingObserver extends ContentObserver implements Listenable {
+    private final UserSettingsProxy mSettingsProxy;
+    private final String mSettingName;
+    private final int mDefaultValue;
+
+    private boolean mListening;
+    private int mUserId;
+    private int mObservedValue;
+
+    protected abstract void handleValueChanged(int value, boolean observedChange);
+
+    public UserSettingObserver(UserSettingsProxy settingsProxy, Handler handler, String settingName,
+            int userId) {
+        this(settingsProxy, handler, settingName, userId, 0);
+    }
+
+    public UserSettingObserver(UserSettingsProxy settingsProxy, Handler handler, String settingName,
+            int userId, int defaultValue) {
+        super(handler);
+        mSettingsProxy = settingsProxy;
+        mSettingName = settingName;
+        mObservedValue = mDefaultValue = defaultValue;
+        mUserId = userId;
+    }
+
+    public int getValue() {
+        return mListening ? mObservedValue : getValueFromProvider();
+    }
+
+    /**
+     * Set the value of the observed setting.
+     *
+     * @param value The new value for the setting.
+     */
+    public void setValue(int value) {
+        mSettingsProxy.putIntForUser(mSettingName, value, mUserId);
+    }
+
+    private int getValueFromProvider() {
+        return mSettingsProxy.getIntForUser(mSettingName, mDefaultValue, mUserId);
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening == mListening) return;
+        mListening = listening;
+        if (listening) {
+            mObservedValue = getValueFromProvider();
+            mSettingsProxy.registerContentObserverForUser(
+                    mSettingsProxy.getUriFor(mSettingName), false, this, mUserId);
+        } else {
+            mSettingsProxy.unregisterContentObserver(this);
+            mObservedValue = mDefaultValue;
+        }
+    }
+
+    @Override
+    public void onChange(boolean selfChange) {
+        final int value = getValueFromProvider();
+        final boolean changed = value != mObservedValue;
+        mObservedValue = value;
+        handleValueChanged(value, changed);
+    }
+
+    /**
+     * Set user handle for which to observe the setting.
+     */
+    public void setUserId(int userId) {
+        mUserId = userId;
+        if (mListening) {
+            setListening(false);
+            setListening(true);
+        }
+    }
+
+    public int getCurrentUser() {
+        return mUserId;
+    }
+
+    public String getKey() {
+        return mSettingName;
+    }
+
+    public boolean isListening() {
+        return mListening;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
index 327e858..ce8db7898 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.qs.dagger;
 
+import android.view.View;
+
+import com.android.systemui.dagger.qualifiers.RootView;
 import com.android.systemui.qs.QSFragmentLegacy;
 
 import dagger.BindsInstance;
@@ -31,6 +34,7 @@
     /** Factory for building a {@link QSFragmentComponent}. */
     @Subcomponent.Factory
     interface Factory {
-        QSFragmentComponent create(@BindsInstance QSFragmentLegacy qsFragment);
+        /** */
+        QSFragmentComponent create(@BindsInstance @RootView View view);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 0c9c24d..0e75b21 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -20,34 +20,17 @@
 import static com.android.systemui.util.Utils.useQsMediaPlayer;
 
 import android.content.Context;
-import android.view.View;
 
-import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.qs.QSFragmentLegacy;
-
-import javax.inject.Named;
-
-import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 
+import javax.inject.Named;
+
 /**
  * Dagger Module for {@link QSFragmentComponent}.
  */
 @Module(includes = {QSScopeModule.class})
 public  interface QSFragmentModule {
-
-    @Provides
-    @RootView
-    static View provideRootView(QSFragmentLegacy qsFragment) {
-        return qsFragment.getView();
-    }
-
-    /** */
-    @Binds
-    QS bindQS(QSFragmentLegacy qsFragment);
-
     /** */
     @Provides
     @Named(QSScopeModule.QS_USING_MEDIA_PLAYER)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 128c237..051eeb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -72,7 +72,8 @@
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 
-public class CustomTile extends QSTileImpl<State> implements TileChangeListener {
+public class CustomTile extends QSTileImpl<State> implements TileChangeListener,
+        CustomTileInterface {
     public static final String PREFIX = "custom(";
 
     private static final long CUSTOM_STALE_TIMEOUT = DateUtils.HOUR_IN_MILLIS;
@@ -181,7 +182,8 @@
     private void updateDefaultTileAndIcon() {
         try {
             PackageManager pm = mUserContext.getPackageManager();
-            int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DIRECT_BOOT_AWARE;
+            int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                    | PackageManager.MATCH_DIRECT_BOOT_AWARE;
             if (isSystemApp(pm)) {
                 flags |= PackageManager.MATCH_DISABLED_COMPONENTS;
             }
@@ -213,7 +215,7 @@
      * Compare two icons, only works for resources.
      */
     private boolean iconEquals(@Nullable android.graphics.drawable.Icon icon1,
-                               @Nullable android.graphics.drawable.Icon icon2) {
+            @Nullable android.graphics.drawable.Icon icon2) {
         if (icon1 == icon2) {
             return true;
         }
@@ -252,10 +254,12 @@
         }
     }
 
+    @Override
     public int getUser() {
         return mUser;
     }
 
+    @Override
     public ComponentName getComponent() {
         return mComponent;
     }
@@ -265,6 +269,7 @@
         return super.populate(logMaker).setComponentName(mComponent);
     }
 
+    @Override
     public Tile getQsTile() {
         // TODO(b/191145007) Move to background thread safely
         updateDefaultTileAndIcon();
@@ -276,6 +281,7 @@
      *
      * @param tile tile populated with state to apply
      */
+    @Override
     public void updateTileState(Tile tile, int appUid) {
         mServiceUid = appUid;
         // This comes from a binder call IQSService.updateQsTile
@@ -310,10 +316,12 @@
         mTile.setState(tile.getState());
     }
 
+    @Override
     public void onDialogShown() {
         mIsShowingDialog = true;
     }
 
+    @Override
     public void onDialogHidden() {
         mIsShowingDialog = false;
         try {
@@ -507,6 +515,7 @@
         return mComponent.getPackageName();
     }
 
+    @Override
     public void startUnlockAndRun() {
         mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
             try {
@@ -518,8 +527,10 @@
 
     /**
      * Starts an {@link android.app.Activity}
+     *
      * @param pendingIntent A PendingIntent for an Activity to be launched immediately.
      */
+    @Override
     public void startActivityAndCollapse(PendingIntent pendingIntent) {
         if (!pendingIntent.isActivity()) {
             Log.i(TAG, "Intent not for activity.");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTileInterface.kt b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTileInterface.kt
new file mode 100644
index 0000000..9e02320
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTileInterface.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.external
+
+import android.app.PendingIntent
+import android.content.ComponentName
+import android.service.quicksettings.Tile
+
+interface CustomTileInterface {
+
+    val user: Int
+    val qsTile: Tile
+    val component: ComponentName
+
+    fun getTileSpec(): String
+
+    fun refreshState()
+    fun updateTileState(tile: Tile, uid: Int)
+
+    fun onDialogShown()
+    fun onDialogHidden()
+
+    fun startActivityAndCollapse(pendingIntent: PendingIntent)
+
+    fun startUnlockAndRun()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 2469a98..78f2da5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -17,6 +17,7 @@
 
 import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT;
 
+import android.app.ActivityManager;
 import android.app.compat.CompatChanges;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -35,6 +36,7 @@
 import android.service.quicksettings.IQSService;
 import android.service.quicksettings.IQSTileService;
 import android.service.quicksettings.TileService;
+import android.text.format.DateUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -81,7 +83,8 @@
 
     // Bind retry control.
     private static final int MAX_BIND_RETRIES = 5;
-    private static final int DEFAULT_BIND_RETRY_DELAY = 1000;
+    private static final long DEFAULT_BIND_RETRY_DELAY = 5 * DateUtils.SECOND_IN_MILLIS;
+    private static final long LOW_MEMORY_BIND_RETRY_DELAY = 20 * DateUtils.SECOND_IN_MILLIS;
 
     // Shared prefs that hold tile lifecycle info.
     private static final String TILES = "tiles_prefs";
@@ -94,6 +97,7 @@
     private final IBinder mToken = new Binder();
     private final PackageManagerAdapter mPackageManagerAdapter;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final ActivityManager mActivityManager;
 
     private Set<Integer> mQueuedMessages = new ArraySet<>();
     @Nullable
@@ -102,7 +106,8 @@
     private IBinder mClickBinder;
 
     private int mBindTryCount;
-    private int mBindRetryDelay = DEFAULT_BIND_RETRY_DELAY;
+    private long mBindRetryDelay = DEFAULT_BIND_RETRY_DELAY;
+    private AtomicBoolean isDeathRebindScheduled = new AtomicBoolean(false);
     private AtomicBoolean mBound = new AtomicBoolean(false);
     private AtomicBoolean mPackageReceiverRegistered = new AtomicBoolean(false);
     private AtomicBoolean mUserReceiverRegistered = new AtomicBoolean(false);
@@ -115,7 +120,7 @@
     @AssistedInject
     TileLifecycleManager(@Main Handler handler, Context context, IQSService service,
             PackageManagerAdapter packageManagerAdapter, BroadcastDispatcher broadcastDispatcher,
-            @Assisted Intent intent, @Assisted UserHandle user,
+            @Assisted Intent intent, @Assisted UserHandle user, ActivityManager activityManager,
             @Background DelayableExecutor executor) {
         mContext = context;
         mHandler = handler;
@@ -126,6 +131,7 @@
         mExecutor = executor;
         mPackageManagerAdapter = packageManagerAdapter;
         mBroadcastDispatcher = broadcastDispatcher;
+        mActivityManager = activityManager;
         if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
     }
 
@@ -152,10 +158,6 @@
         }
     }
 
-    public void setBindRetryDelay(int delayMs) {
-        mBindRetryDelay = delayMs;
-    }
-
     public boolean isActiveTile() {
         try {
             ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
@@ -250,19 +252,15 @@
 
     private boolean bindServices() {
         String packageName = mIntent.getComponent().getPackageName();
+        int flags = Context.BIND_AUTO_CREATE
+                | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+                | Context.BIND_WAIVE_PRIORITY;
         if (CompatChanges.isChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, packageName,
                 mUser)) {
-            return mContext.bindServiceAsUser(mIntent, this,
-                    Context.BIND_AUTO_CREATE
-                            | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
-                            | Context.BIND_WAIVE_PRIORITY,
-                    mUser);
+            return mContext.bindServiceAsUser(mIntent, this, flags, mUser);
         }
         return mContext.bindServiceAsUser(mIntent, this,
-                Context.BIND_AUTO_CREATE
-                        | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
-                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
-                        | Context.BIND_WAIVE_PRIORITY,
+                flags | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
                 mUser);
     }
 
@@ -352,10 +350,34 @@
         if (!mBound.get()) return;
         if (DEBUG) Log.d(TAG, "handleDeath");
         if (checkComponentState()) {
-            mExecutor.executeDelayed(() -> setBindService(true), mBindRetryDelay);
+            if (isDeathRebindScheduled.compareAndSet(false, true)) {
+                mExecutor.executeDelayed(() -> {
+                    setBindService(true);
+                    isDeathRebindScheduled.set(false);
+                }, getRebindDelay());
+            }
         }
     }
 
+    /**
+     * @return the delay to automatically rebind after a service died. It provides a longer delay if
+     * the device is a low memory state because the service is likely to get killed again by the
+     * system. In this case we want to rebind later and not to cause a loop of a frequent rebinds.
+     */
+    private long getRebindDelay() {
+        final ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
+        mActivityManager.getMemoryInfo(info);
+
+        final long delay;
+        if (info.lowMemory) {
+            delay = LOW_MEMORY_BIND_RETRY_DELAY;
+        } else {
+            delay = mBindRetryDelay;
+        }
+        Log.i(TAG, "Rebinding with a delay=" + delay);
+        return delay;
+    }
+
     private boolean checkComponentState() {
         if (!isPackageAvailable() || !isComponentAvailable()) {
             startPackageListening();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 941a9d6..3ee4a1b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -75,13 +75,12 @@
     private boolean mStarted = false;
 
     TileServiceManager(TileServices tileServices, Handler handler, ComponentName component,
-            BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
-            CustomTileAddedRepository customTileAddedRepository, DelayableExecutor executor) {
+            UserTracker userTracker, TileLifecycleManager.Factory tileLifecycleManagerFactory,
+            CustomTileAddedRepository customTileAddedRepository) {
         this(tileServices, handler, userTracker, customTileAddedRepository,
-                new TileLifecycleManager(handler, tileServices.getContext(), tileServices,
-                        new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher,
+                tileLifecycleManagerFactory.create(
                         new Intent(TileService.ACTION_QS_TILE).setComponent(component),
-                        userTracker.getUserHandle(), executor));
+                        userTracker.getUserHandle()));
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index fc24022..c3744df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -67,9 +67,10 @@
     static final int REDUCED_MAX_BOUND = 1;
     private static final String TAG = "TileServices";
 
-    private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
-    private final SparseArrayMap<ComponentName, CustomTile> mTiles = new SparseArrayMap<>();
-    private final ArrayMap<IBinder, CustomTile> mTokenMap = new ArrayMap<>();
+    private final ArrayMap<CustomTileInterface, TileServiceManager> mServices = new ArrayMap<>();
+    private final SparseArrayMap<ComponentName, CustomTileInterface> mTiles =
+            new SparseArrayMap<>();
+    private final ArrayMap<IBinder, CustomTileInterface> mTokenMap = new ArrayMap<>();
     private final Context mContext;
     private final Handler mMainHandler;
     private final Provider<Handler> mHandlerProvider;
@@ -80,6 +81,7 @@
     private final UserTracker mUserTracker;
     private final StatusBarIconController mStatusBarIconController;
     private final PanelInteractor mPanelInteractor;
+    private final TileLifecycleManager.Factory mTileLifecycleManagerFactory;
     private final CustomTileAddedRepository mCustomTileAddedRepository;
     private final DelayableExecutor mBackgroundExecutor;
 
@@ -95,6 +97,7 @@
             CommandQueue commandQueue,
             StatusBarIconController statusBarIconController,
             PanelInteractor panelInteractor,
+            TileLifecycleManager.Factory tileLifecycleManagerFactory,
             CustomTileAddedRepository customTileAddedRepository,
             @Background DelayableExecutor backgroundExecutor) {
         mHost = host;
@@ -108,6 +111,7 @@
         mStatusBarIconController = statusBarIconController;
         mCommandQueue.addCallback(mRequestListeningCallback);
         mPanelInteractor = panelInteractor;
+        mTileLifecycleManagerFactory = tileLifecycleManagerFactory;
         mCustomTileAddedRepository = customTileAddedRepository;
         mBackgroundExecutor = backgroundExecutor;
     }
@@ -120,7 +124,7 @@
         return mHost;
     }
 
-    public TileServiceManager getTileWrapper(CustomTile tile) {
+    public TileServiceManager getTileWrapper(CustomTileInterface tile) {
         ComponentName component = tile.getComponent();
         int userId = tile.getUser();
         TileServiceManager service = onCreateTileService(component, mBroadcastDispatcher);
@@ -136,11 +140,11 @@
 
     protected TileServiceManager onCreateTileService(ComponentName component,
             BroadcastDispatcher broadcastDispatcher) {
-        return new TileServiceManager(this, mHandlerProvider.get(), component,
-                broadcastDispatcher, mUserTracker, mCustomTileAddedRepository, mBackgroundExecutor);
+        return new TileServiceManager(this, mHandlerProvider.get(), component, mUserTracker,
+                mTileLifecycleManagerFactory, mCustomTileAddedRepository);
     }
 
-    public void freeService(CustomTile tile, TileServiceManager service) {
+    public void freeService(CustomTileInterface tile, TileServiceManager service) {
         synchronized (mServices) {
             service.setBindAllowed(false);
             service.handleDestroy();
@@ -184,7 +188,7 @@
         }
     }
 
-    private int verifyCaller(CustomTile tile) {
+    private int verifyCaller(CustomTileInterface tile) {
         try {
             String packageName = tile.getComponent().getPackageName();
             int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
@@ -201,7 +205,7 @@
     private void requestListening(ComponentName component) {
         synchronized (mServices) {
             int userId = mUserTracker.getUserId();
-            CustomTile customTile = getTileForUserAndComponent(userId, component);
+            CustomTileInterface customTile = getTileForUserAndComponent(userId, component);
             if (customTile == null) {
                 Log.d(TAG, "Couldn't find tile for " + component + "(" + userId + ")");
                 return;
@@ -227,7 +231,7 @@
 
     @Override
     public void updateQsTile(Tile tile, IBinder token) {
-        CustomTile customTile = getTileForToken(token);
+        CustomTileInterface customTile = getTileForToken(token);
         if (customTile != null) {
             int uid = verifyCaller(customTile);
             synchronized (mServices) {
@@ -247,7 +251,7 @@
 
     @Override
     public void onStartSuccessful(IBinder token) {
-        CustomTile customTile = getTileForToken(token);
+        CustomTileInterface customTile = getTileForToken(token);
         if (customTile != null) {
             verifyCaller(customTile);
             synchronized (mServices) {
@@ -267,7 +271,7 @@
 
     @Override
     public void onShowDialog(IBinder token) {
-        CustomTile customTile = getTileForToken(token);
+        CustomTileInterface customTile = getTileForToken(token);
         if (customTile != null) {
             verifyCaller(customTile);
             customTile.onDialogShown();
@@ -278,7 +282,7 @@
 
     @Override
     public void onDialogHidden(IBinder token) {
-        CustomTile customTile = getTileForToken(token);
+        CustomTileInterface customTile = getTileForToken(token);
         if (customTile != null) {
             verifyCaller(customTile);
             Objects.requireNonNull(mServices.get(customTile)).setShowingDialog(false);
@@ -288,7 +292,7 @@
 
     @Override
     public void onStartActivity(IBinder token) {
-        CustomTile customTile = getTileForToken(token);
+        CustomTileInterface customTile = getTileForToken(token);
         if (customTile != null) {
             verifyCaller(customTile);
             mPanelInteractor.forceCollapsePanels();
@@ -301,7 +305,7 @@
     }
 
     @VisibleForTesting
-    protected void startActivity(CustomTile customTile, PendingIntent pendingIntent) {
+    protected void startActivity(CustomTileInterface customTile, PendingIntent pendingIntent) {
         if (customTile != null) {
             verifyCaller(customTile);
             customTile.startActivityAndCollapse(pendingIntent);
@@ -310,7 +314,7 @@
 
     @Override
     public void updateStatusIcon(IBinder token, Icon icon, String contentDescription) {
-        CustomTile customTile = getTileForToken(token);
+        CustomTileInterface customTile = getTileForToken(token);
         if (customTile != null) {
             verifyCaller(customTile);
             try {
@@ -322,7 +326,7 @@
                 if (info.applicationInfo.isSystemApp()) {
                     final StatusBarIcon statusIcon = icon != null
                             ? new StatusBarIcon(userHandle, packageName, icon, 0, 0,
-                                    contentDescription)
+                            contentDescription)
                             : null;
                     final String slot = getStatusBarIconSlotName(componentName);
                     mMainHandler.post(new Runnable() {
@@ -340,7 +344,7 @@
     @Nullable
     @Override
     public Tile getTile(IBinder token) {
-        CustomTile customTile = getTileForToken(token);
+        CustomTileInterface customTile = getTileForToken(token);
         if (customTile != null) {
             verifyCaller(customTile);
             return customTile.getQsTile();
@@ -355,11 +359,11 @@
         synchronized (mServices) {
             mTokenMap.forEach((iBinder, customTile) ->
                     sb.append(iBinder.toString())
-                    .append(":")
-                    .append(customTile.getComponent().flattenToShortString())
-                    .append(":")
-                    .append(customTile.getUser())
-                    .append(","));
+                            .append(":")
+                            .append(customTile.getComponent().flattenToShortString())
+                            .append(":")
+                            .append(customTile.getUser())
+                            .append(","));
         }
         sb.append("]");
         return sb.toString();
@@ -367,7 +371,7 @@
 
     @Override
     public void startUnlockAndRun(IBinder token) {
-        CustomTile customTile = getTileForToken(token);
+        CustomTileInterface customTile = getTileForToken(token);
         if (customTile != null) {
             verifyCaller(customTile);
             customTile.startUnlockAndRun();
@@ -385,14 +389,14 @@
     }
 
     @Nullable
-    public CustomTile getTileForToken(IBinder token) {
+    public CustomTileInterface getTileForToken(IBinder token) {
         synchronized (mServices) {
             return mTokenMap.get(token);
         }
     }
 
     @Nullable
-    private CustomTile getTileForUserAndComponent(int userId, ComponentName component) {
+    private CustomTileInterface getTileForUserAndComponent(int userId, ComponentName component) {
         synchronized (mServices) {
             return mTiles.get(userId, component);
         }
@@ -419,11 +423,6 @@
     };
 
     private static final Comparator<TileServiceManager> SERVICE_SORT =
-            new Comparator<TileServiceManager>() {
-        @Override
-        public int compare(TileServiceManager left, TileServiceManager right) {
-            return -Integer.compare(left.getBindPriority(), right.getBindPriority());
-        }
-    };
+            (left, right) -> -Integer.compare(left.getBindPriority(), right.getBindPriority());
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/dagger/FooterActionsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/dagger/FooterActionsModule.kt
index 38fe34e..42d3f81 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/dagger/FooterActionsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/dagger/FooterActionsModule.kt
@@ -18,8 +18,6 @@
 
 import com.android.systemui.qs.footer.data.repository.ForegroundServicesRepository
 import com.android.systemui.qs.footer.data.repository.ForegroundServicesRepositoryImpl
-import com.android.systemui.qs.footer.data.repository.UserSwitcherRepository
-import com.android.systemui.qs.footer.data.repository.UserSwitcherRepositoryImpl
 import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
 import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractorImpl
 import dagger.Binds
@@ -28,7 +26,6 @@
 /** Dagger module to provide/bind footer actions singletons. */
 @Module
 interface FooterActionsModule {
-    @Binds fun userSwitcherRepository(impl: UserSwitcherRepositoryImpl): UserSwitcherRepository
 
     @Binds
     fun foregroundServicesRepository(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
index 8b2c3de..c91ed13 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
@@ -38,10 +38,10 @@
 import com.android.systemui.qs.QSSecurityFooterUtils
 import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
 import com.android.systemui.qs.footer.data.repository.ForegroundServicesRepository
-import com.android.systemui.qs.footer.data.repository.UserSwitcherRepository
 import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
 import com.android.systemui.security.data.repository.SecurityRepository
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.user.data.repository.UserSwitcherRepository
 import com.android.systemui.user.domain.interactor.UserInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
index c5512c1..4bb8c6e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
@@ -272,7 +272,6 @@
                             // repository
                             launch { tileSpecRepository.setTiles(currentUser.value, resolvedSpecs) }
                         }
-                        Log.d("Fabian", "Finished resolving tiles")
                     }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index fb71cef..17251c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -36,7 +36,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -49,6 +48,7 @@
 import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.settings.GlobalSettings;
 
@@ -56,8 +56,6 @@
 
 import javax.inject.Inject;
 
-
-
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTileImpl<BooleanState> {
 
@@ -90,8 +88,7 @@
         mBroadcastDispatcher = broadcastDispatcher;
         mLazyConnectivityManager = lazyConnectivityManager;
 
-        mSetting = new SettingObserver(globalSettings, mHandler, Global.AIRPLANE_MODE_ON,
-                userTracker.getUserId()) {
+        mSetting = new SettingObserver(globalSettings, mHandler, Global.AIRPLANE_MODE_ON) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
                 // mHandler is the background handler so calling this is OK
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 18d472b..426aa55 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -29,7 +29,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -38,9 +37,10 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -53,7 +53,7 @@
 
     private final BatteryController mBatteryController;
     @VisibleForTesting
-    protected final SettingObserver mSetting;
+    protected final UserSettingObserver mSetting;
 
     private int mLevel;
     private boolean mPowerSave;
@@ -79,7 +79,7 @@
         mBatteryController = batteryController;
         mBatteryController.observe(getLifecycle(), this);
         int currentUser = host.getUserContext().getUserId();
-        mSetting = new SettingObserver(
+        mSetting = new UserSettingObserver(
                 secureSettings,
                 mHandler,
                 Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
index ee57b2b..c8adbfc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
@@ -28,8 +28,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
-import com.android.systemui.res.R.drawable;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -38,9 +36,10 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -51,8 +50,8 @@
 
     public static final String TILE_SPEC = "color_correction";
 
-    private final Icon mIcon = ResourceIcon.get(drawable.ic_qs_color_correction);
-    private final SettingObserver mSetting;
+    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_color_correction);
+    private final UserSettingObserver mSetting;
 
     @Inject
     public ColorCorrectionTile(
@@ -71,7 +70,7 @@
         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
 
-        mSetting = new SettingObserver(secureSettings, mHandler,
+        mSetting = new UserSettingObserver(secureSettings, mHandler,
                 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, userTracker.getUserId()) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 993ada6..c34a584 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -29,8 +29,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
-import com.android.systemui.res.R.drawable;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -39,9 +37,10 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -51,7 +50,7 @@
 public class ColorInversionTile extends QSTileImpl<BooleanState> {
 
     public static final String TILE_SPEC = "inversion";
-    private final SettingObserver mSetting;
+    private final UserSettingObserver mSetting;
 
     @Inject
     public ColorInversionTile(
@@ -70,7 +69,7 @@
         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
 
-        mSetting = new SettingObserver(secureSettings, mHandler,
+        mSetting = new UserSettingObserver(secureSettings, mHandler,
                 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
@@ -126,8 +125,8 @@
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.quick_settings_inversion_label);
         state.icon = ResourceIcon.get(state.value
-                ? drawable.qs_invert_colors_icon_on
-                : drawable.qs_invert_colors_icon_off);
+                ? R.drawable.qs_invert_colors_icon_on
+                : R.drawable.qs_invert_colors_icon_off);
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.contentDescription = state.label;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 0617b30..f6518d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -45,7 +45,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.notification.EnableZenModeDialog;
 import com.android.systemui.Prefs;
-import com.android.systemui.res.R;
 import com.android.systemui.animation.DialogCuj;
 import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -56,10 +55,11 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.qs.tiles.dialog.QSZenModeDialogMetricsLogger;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.settings.SecureSettings;
@@ -81,7 +81,7 @@
 
     private final ZenModeController mController;
     private final SharedPreferences mSharedPreferences;
-    private final SettingObserver mSettingZenDuration;
+    private final UserSettingObserver mSettingZenDuration;
     private final DialogLaunchAnimator mDialogLaunchAnimator;
     private final QSZenModeDialogMetricsLogger mQSZenDialogMetricsLogger;
 
@@ -109,7 +109,7 @@
         mSharedPreferences = sharedPreferences;
         mController.observe(getLifecycle(), mZenCallback);
         mDialogLaunchAnimator = dialogLaunchAnimator;
-        mSettingZenDuration = new SettingObserver(secureSettings, mUiHandler,
+        mSettingZenDuration = new UserSettingObserver(secureSettings, mUiHandler,
                 Settings.Secure.ZEN_DURATION, getHost().getUserId()) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
index a08b3fc..4f0a63b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
@@ -38,7 +38,6 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -49,9 +48,10 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -69,8 +69,8 @@
     private final Icon mIconUndocked = ResourceIcon.get(R.drawable.ic_qs_screen_saver_undocked);
     private final IDreamManager mDreamManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
-    private final SettingObserver mEnabledSettingObserver;
-    private final SettingObserver mDreamSettingObserver;
+    private final UserSettingObserver mEnabledSettingObserver;
+    private final UserSettingObserver mDreamSettingObserver;
     private final UserTracker mUserTracker;
     private final boolean mDreamSupported;
     private final boolean mDreamOnlyEnabledForDockUser;
@@ -111,14 +111,14 @@
                 statusBarStateController, activityStarter, qsLogger);
         mDreamManager = dreamManager;
         mBroadcastDispatcher = broadcastDispatcher;
-        mEnabledSettingObserver = new SettingObserver(secureSettings, mHandler,
+        mEnabledSettingObserver = new UserSettingObserver(secureSettings, mHandler,
                 Settings.Secure.SCREENSAVER_ENABLED, userTracker.getUserId()) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
                 refreshState();
             }
         };
-        mDreamSettingObserver = new SettingObserver(secureSettings, mHandler,
+        mDreamSettingObserver = new UserSettingObserver(secureSettings, mHandler,
                 Settings.Secure.SCREENSAVER_COMPONENTS, userTracker.getUserId()) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java
index 78af976..b08e6a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java
@@ -28,7 +28,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -37,9 +36,10 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.settings.SecureSettings;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -53,7 +53,7 @@
 
     private final Icon mIcon = ResourceIcon.get(
             com.android.internal.R.drawable.ic_qs_one_handed_mode);
-    private final SettingObserver mSetting;
+    private final UserSettingObserver mSetting;
 
     @Inject
     public OneHandedModeTile(
@@ -70,7 +70,7 @@
             SecureSettings secureSettings) {
         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
-        mSetting = new SettingObserver(secureSettings, mHandler,
+        mSetting = new UserSettingObserver(secureSettings, mHandler,
                 Settings.Secure.ONE_HANDED_MODE_ENABLED, userTracker.getUserId()) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 5a95004..f1d8f9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -36,7 +36,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -45,9 +44,10 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
@@ -67,7 +67,7 @@
     private final RotationLockController mController;
     private final SensorPrivacyManager mPrivacyManager;
     private final BatteryController mBatteryController;
-    private final SettingObserver mSetting;
+    private final UserSettingObserver mSetting;
     private final boolean mAllowRotationResolver;
 
     @Inject
@@ -93,7 +93,7 @@
         mPrivacyManager = privacyManager;
         mBatteryController = batteryController;
         int currentUser = host.getUserContext().getUserId();
-        mSetting = new SettingObserver(
+        mSetting = new UserSettingObserver(
                 secureSettings,
                 mHandler,
                 Secure.CAMERA_AUTOROTATE,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalytics.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalytics.kt
new file mode 100644
index 0000000..0d15a5b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalytics.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.analytics
+
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.QSEvent
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+
+/** Tracks QS tiles analytic events to [UiEventLogger]. */
+@SysUISingleton
+class QSTileAnalytics
+@Inject
+constructor(
+    private val uiEventLogger: UiEventLogger,
+) {
+
+    fun trackUserAction(config: QSTileConfig, action: QSTileUserAction) {
+        logAction(config, action)
+    }
+
+    private fun logAction(config: QSTileConfig, action: QSTileUserAction) {
+        uiEventLogger.logWithInstanceId(
+            action.getQSEvent(),
+            0,
+            config.metricsSpec,
+            config.instanceId,
+        )
+    }
+
+    private fun QSTileUserAction.getQSEvent(): QSEvent =
+        when (this) {
+            is QSTileUserAction.Click -> QSEvent.QS_ACTION_CLICK
+            is QSTileUserAction.LongClick -> QSEvent.QS_ACTION_LONG_PRESS
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt
new file mode 100644
index 0000000..70a683b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.logging
+
+import androidx.annotation.GuardedBy
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.QSTilesDefaultLog
+import com.android.systemui.log.dagger.QSTilesLogBuffers
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.base.interactor.StateUpdateTrigger
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import com.android.systemui.statusbar.StatusBarState
+import javax.inject.Inject
+import javax.inject.Provider
+
+@SysUISingleton
+class QSTileLogger
+@Inject
+constructor(
+    @QSTilesLogBuffers logBuffers: Map<TileSpec, LogBuffer>,
+    @QSTilesDefaultLog private val defaultLogBufferProvider: Provider<LogBuffer>,
+    private val mStatusBarStateController: StatusBarStateController,
+) {
+    @GuardedBy("logBufferCache") private val logBufferCache = logBuffers.toMutableMap()
+
+    /**
+     * Tracks user action when it's first received by the ViewModel and before it reaches the
+     * pipeline
+     */
+    fun logUserAction(
+        userAction: QSTileUserAction,
+        tileSpec: TileSpec,
+        hasData: Boolean,
+        hasTileState: Boolean,
+    ) {
+        tileSpec
+            .getLogBuffer()
+            .log(
+                tileSpec.getLogTag(),
+                LogLevel.DEBUG,
+                {
+                    str1 = userAction.toLogString()
+                    int1 = mStatusBarStateController.state
+                    bool1 = hasTileState
+                    bool2 = hasData
+                },
+                {
+                    "tile $str1: " +
+                        "statusBarState=${StatusBarState.toString(int1)}, " +
+                        "hasState=$bool1, " +
+                        "hasData=$bool2"
+                }
+            )
+    }
+
+    /** Tracks user action when it's rejected by false gestures */
+    fun logUserActionRejectedByFalsing(
+        userAction: QSTileUserAction,
+        tileSpec: TileSpec,
+    ) {
+        tileSpec
+            .getLogBuffer()
+            .log(
+                tileSpec.getLogTag(),
+                LogLevel.DEBUG,
+                { str1 = userAction.toLogString() },
+                { "tile $str1: rejected by falsing" }
+            )
+    }
+
+    /** Tracks user action when it's rejected according to the policy */
+    fun logUserActionRejectedByPolicy(
+        userAction: QSTileUserAction,
+        tileSpec: TileSpec,
+    ) {
+        tileSpec
+            .getLogBuffer()
+            .log(
+                tileSpec.getLogTag(),
+                LogLevel.DEBUG,
+                { str1 = userAction.toLogString() },
+                { "tile $str1: rejected by policy" }
+            )
+    }
+
+    /**
+     * Tracks user actions when it reaches the pipeline and mixes with the last tile state and data
+     */
+    fun <T> logUserActionPipeline(
+        tileSpec: TileSpec,
+        userAction: QSTileUserAction,
+        tileState: QSTileState,
+        data: T,
+    ) {
+        tileSpec
+            .getLogBuffer()
+            .log(
+                tileSpec.getLogTag(),
+                LogLevel.DEBUG,
+                {
+                    str1 = userAction.toLogString()
+                    str2 = tileState.toLogString()
+                    str3 = data.toString().take(DATA_MAX_LENGTH)
+                },
+                {
+                    "tile $str1 pipeline: " +
+                        "statusBarState=${StatusBarState.toString(int1)}, " +
+                        "state=$str2, " +
+                        "data=$str3"
+                }
+            )
+    }
+
+    /** Tracks state changes based on the data and trigger event. */
+    fun <T> logStateUpdate(
+        tileSpec: TileSpec,
+        trigger: StateUpdateTrigger,
+        tileState: QSTileState,
+        data: T,
+    ) {
+        tileSpec
+            .getLogBuffer()
+            .log(
+                tileSpec.getLogTag(),
+                LogLevel.DEBUG,
+                {
+                    str1 = trigger.toLogString()
+                    str2 = tileState.toLogString()
+                    str3 = data.toString().take(DATA_MAX_LENGTH)
+                },
+                { "tile state update: trigger=$str1, state=$str2, data=$str3" }
+            )
+    }
+
+    private fun TileSpec.getLogTag(): String = "${TAG_FORMAT_PREFIX}_${this.spec}"
+
+    private fun TileSpec.getLogBuffer(): LogBuffer =
+        synchronized(logBufferCache) {
+            logBufferCache.getOrPut(this) { defaultLogBufferProvider.get() }
+        }
+
+    private fun StateUpdateTrigger.toLogString(): String =
+        when (this) {
+            is StateUpdateTrigger.ForceUpdate -> "force"
+            is StateUpdateTrigger.InitialRequest -> "init"
+            is StateUpdateTrigger.UserAction<*> -> action.toLogString()
+        }
+
+    private fun QSTileUserAction.toLogString(): String =
+        when (this) {
+            is QSTileUserAction.Click -> "click"
+            is QSTileUserAction.LongClick -> "long click"
+        }
+
+    /* Shortened version of a data class toString() */
+    private fun QSTileState.toLogString(): String =
+        "[label=$label, " +
+            "state=$activationState, " +
+            "s_label=$secondaryLabel, " +
+            "cd=$contentDescription, " +
+            "sd=$stateDescription, " +
+            "svi=$sideViewIcon, " +
+            "enabled=$enabledState, " +
+            "a11y=$expandedAccessibilityClassName" +
+            "]"
+
+    private companion object {
+        const val TAG_FORMAT_PREFIX = "QSLog"
+        const val DATA_MAX_LENGTH = 50
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt
index 58a335e..2114751 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt
@@ -20,12 +20,15 @@
 import androidx.annotation.VisibleForTesting
 import com.android.internal.util.Preconditions
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
 import com.android.systemui.qs.tiles.base.interactor.DisabledByPolicyInteractor
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataRequest
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
 import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
 import com.android.systemui.qs.tiles.base.interactor.StateUpdateTrigger
+import com.android.systemui.qs.tiles.base.logging.QSTileLogger
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
 import com.android.systemui.qs.tiles.viewmodel.QSTileLifecycle
 import com.android.systemui.qs.tiles.viewmodel.QSTilePolicy
@@ -33,6 +36,7 @@
 import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
 import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
 import com.android.systemui.util.kotlin.sample
+import com.android.systemui.util.kotlin.throttle
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedInject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -70,6 +74,9 @@
     private val tileDataInteractor: QSTileDataInteractor<DATA_TYPE>,
     private val mapper: QSTileDataToStateMapper<DATA_TYPE>,
     private val disabledByPolicyInteractor: DisabledByPolicyInteractor,
+    private val falsingManager: FalsingManager,
+    private val qsTileAnalytics: QSTileAnalytics,
+    private val qsTileLogger: QSTileLogger,
     private val backgroundDispatcher: CoroutineDispatcher,
     private val tileScope: CoroutineScope,
 ) : QSTileViewModel {
@@ -81,6 +88,9 @@
         @Assisted tileDataInteractor: QSTileDataInteractor<DATA_TYPE>,
         @Assisted mapper: QSTileDataToStateMapper<DATA_TYPE>,
         disabledByPolicyInteractor: DisabledByPolicyInteractor,
+        falsingManager: FalsingManager,
+        qsTileAnalytics: QSTileAnalytics,
+        qsTileLogger: QSTileLogger,
         @Background backgroundDispatcher: CoroutineDispatcher,
     ) : this(
         config,
@@ -88,6 +98,9 @@
         tileDataInteractor,
         mapper,
         disabledByPolicyInteractor,
+        falsingManager,
+        qsTileAnalytics,
+        qsTileLogger,
         backgroundDispatcher,
         CoroutineScope(SupervisorJob())
     )
@@ -98,8 +111,10 @@
         MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
     private val forceUpdates: MutableSharedFlow<Unit> =
         MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+    private val spec
+        get() = config.tileSpec
 
-    private lateinit var tileData: SharedFlow<DATA_TYPE>
+    private lateinit var tileData: SharedFlow<DataWithTrigger<DATA_TYPE>>
 
     override lateinit var state: SharedFlow<QSTileState>
     override val isAvailable: StateFlow<Boolean> =
@@ -128,8 +143,14 @@
 
     @CallSuper
     override fun onActionPerformed(userAction: QSTileUserAction) {
-        Preconditions.checkState(tileData.replayCache.isNotEmpty())
         Preconditions.checkState(currentLifeState == QSTileLifecycle.ALIVE)
+
+        qsTileLogger.logUserAction(
+            userAction,
+            spec,
+            tileData.replayCache.isNotEmpty(),
+            state.replayCache.isNotEmpty()
+        )
         userInputs.tryEmit(userAction)
     }
 
@@ -142,7 +163,16 @@
                 state =
                     tileData
                         // TODO(b/299908705): log data and corresponding tile state
-                        .map { mapper.map(config, it) }
+                        .map { dataWithTrigger ->
+                            mapper.map(config, dataWithTrigger.data).also { state ->
+                                qsTileLogger.logStateUpdate(
+                                    spec,
+                                    dataWithTrigger.trigger,
+                                    state,
+                                    dataWithTrigger.data
+                                )
+                            }
+                        }
                         .flowOn(backgroundDispatcher)
                         .shareIn(
                             tileScope,
@@ -158,7 +188,7 @@
         currentLifeState = lifecycle
     }
 
-    private fun createTileDataFlow(): SharedFlow<DATA_TYPE> =
+    private fun createTileDataFlow(): SharedFlow<DataWithTrigger<DATA_TYPE>> =
         userIds
             .flatMapLatest { userId ->
                 merge(
@@ -180,7 +210,7 @@
                         request.trigger.tileData as DATA_TYPE,
                     )
                 }
-                dataFlow
+                dataFlow.map { DataWithTrigger(it, request.trigger) }
             }
             .flowOn(backgroundDispatcher)
             .shareIn(
@@ -193,21 +223,53 @@
         data class StateWithData<T>(val state: QSTileState, val data: T)
 
         return when (config.policy) {
-            is QSTilePolicy.NoRestrictions -> userInputs
-            is QSTilePolicy.Restricted ->
-                userInputs.filter {
-                    val result =
-                        disabledByPolicyInteractor.isDisabled(userId, config.policy.userRestriction)
-                    !disabledByPolicyInteractor.handlePolicyResult(result)
+                is QSTilePolicy.NoRestrictions -> userInputs
+                is QSTilePolicy.Restricted ->
+                    userInputs.filter { action ->
+                        val result =
+                            disabledByPolicyInteractor.isDisabled(
+                                userId,
+                                config.policy.userRestriction
+                            )
+                        !disabledByPolicyInteractor.handlePolicyResult(result).also { isDisabled ->
+                            if (isDisabled) {
+                                qsTileLogger.logUserActionRejectedByPolicy(action, spec)
+                            }
+                        }
+                    }
+            }
+            .filter { action ->
+                val isFalseAction =
+                    when (action) {
+                        is QSTileUserAction.Click ->
+                            falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)
+                        is QSTileUserAction.LongClick ->
+                            falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)
+                    }
+                if (isFalseAction) {
+                    qsTileLogger.logUserActionRejectedByFalsing(action, spec)
                 }
-        // Skip the input until there is some data
-        }.sample(state.combine(tileData) { state, data -> StateWithData(state, data) }) {
-            input,
-            stateWithData ->
-            StateUpdateTrigger.UserAction(input, stateWithData.state, stateWithData.data)
-        }
+                !isFalseAction
+            }
+            .throttle(500)
+            // Skip the input until there is some data
+            .sample(state.combine(tileData) { state, data -> StateWithData(state, data) }) {
+                input,
+                stateWithData ->
+                StateUpdateTrigger.UserAction(input, stateWithData.state, stateWithData.data).also {
+                    qsTileLogger.logUserActionPipeline(
+                        spec,
+                        it.action,
+                        stateWithData.state,
+                        stateWithData.data
+                    )
+                    qsTileAnalytics.trackUserAction(config, it.action)
+                }
+            }
     }
 
+    private data class DataWithTrigger<T>(val data: T, val trigger: StateUpdateTrigger)
+
     interface Factory<T> {
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
index 8ae2dc2..80af76d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
@@ -102,9 +102,10 @@
         showSeeAll: Boolean,
         showPairNewDevice: Boolean
     ) {
-        seeAllViewGroup.visibility = if (showSeeAll) VISIBLE else GONE
-        pairNewDeviceViewGroup.visibility = if (showPairNewDevice) VISIBLE else GONE
-        deviceItemAdapter.refreshDeviceItemList(deviceItem)
+        deviceItemAdapter.refreshDeviceItemList(deviceItem) {
+            seeAllViewGroup.visibility = if (showSeeAll) VISIBLE else GONE
+            pairNewDeviceViewGroup.visibility = if (showPairNewDevice) VISIBLE else GONE
+        }
     }
 
     internal fun onBluetoothStateUpdated(isEnabled: Boolean, subtitleResId: Int) {
@@ -173,8 +174,8 @@
 
         internal fun getItem(position: Int) = asyncListDiffer.currentList[position]
 
-        internal fun refreshDeviceItemList(updated: List<DeviceItem>) {
-            asyncListDiffer.submitList(updated)
+        internal fun refreshDeviceItemList(updated: List<DeviceItem>, callback: () -> Unit) {
+            asyncListDiffer.submitList(updated, callback)
         }
 
         internal inner class DeviceItemViewHolder(view: View) : RecyclerView.ViewHolder(view) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
index 97e1783..8e27493 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
@@ -113,7 +113,6 @@
                     .launchIn(this)
 
                 deviceItemInteractor.deviceItemUpdate
-                    .filterNotNull()
                     .onEach {
                         dialog!!.onDeviceItemUpdated(
                             it.take(MAX_DEVICE_ITEM_ENTRY),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
index 14d24f9..e196c6c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
@@ -34,10 +34,10 @@
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.SharedFlow
 import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.shareIn
 import kotlinx.coroutines.withContext
 
@@ -55,10 +55,10 @@
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) {
 
-    private val mutableDeviceItemUpdate: MutableStateFlow<List<DeviceItem>?> =
-        MutableStateFlow(null)
+    private val mutableDeviceItemUpdate: MutableSharedFlow<List<DeviceItem>> =
+        MutableSharedFlow(extraBufferCapacity = 1)
     internal val deviceItemUpdate
-        get() = mutableDeviceItemUpdate.asStateFlow()
+        get() = mutableDeviceItemUpdate.asSharedFlow()
 
     internal val deviceItemUpdateRequest: SharedFlow<Unit> =
         conflatedCallbackFlow {
@@ -119,16 +119,15 @@
 
     internal suspend fun updateDeviceItems(context: Context) {
         withContext(backgroundDispatcher) {
-            val mostRecentlyConnectedDevices = bluetoothAdapter?.mostRecentlyConnectedDevices
-
-            mutableDeviceItemUpdate.value =
+            mutableDeviceItemUpdate.tryEmit(
                 bluetoothTileDialogRepository.cachedDevices
                     .mapNotNull { cachedDevice ->
                         deviceItemFactoryList
                             .firstOrNull { it.isFilterMatched(cachedDevice, audioManager) }
                             ?.create(context, cachedDevice)
                     }
-                    .sort(displayPriority, mostRecentlyConnectedDevices)
+                    .sort(displayPriority, bluetoothAdapter?.mostRecentlyConnectedDevices)
+            )
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
index 1a6cf99..4a3bcae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
@@ -26,6 +26,7 @@
     val tileIcon: Icon,
     @StringRes val tileLabelRes: Int,
     val instanceId: InstanceId,
+    val metricsSpec: String = tileSpec.spec,
     val policy: QSTilePolicy = QSTilePolicy.NoRestrictions,
 )
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 584456d..91b4d17 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -51,7 +52,6 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.launch
-import javax.inject.Inject
 
 /**
  * Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI
@@ -142,7 +142,7 @@
                                 // When the device becomes unlocked in Lockscreen, go to Gone if
                                 // bypass is enabled.
                                 renderedScenes.contains(SceneKey.Lockscreen) ->
-                                    if (deviceEntryInteractor.isBypassEnabled()) {
+                                    if (deviceEntryInteractor.isBypassEnabled.value) {
                                         SceneKey.Gone to
                                             "device unlocked in Lockscreen scene with bypass"
                                     } else {
@@ -179,36 +179,34 @@
         }
 
         applicationScope.launch {
-            powerInteractor.isAsleep
-                .collect { isAsleep ->
-                    if (isAsleep) {
-                        switchToScene(
-                                targetSceneKey = SceneKey.Lockscreen,
-                                loggingReason = "device is starting to sleep",
-                        )
-                    } else {
-                        val authMethod = authenticationInteractor.getAuthenticationMethod()
-                        val isUnlocked = deviceEntryInteractor.isUnlocked.value
-                        when {
-                            authMethod == AuthenticationMethodModel.None -> {
-                                switchToScene(
-                                        targetSceneKey = SceneKey.Gone,
-                                        loggingReason =
-                                        "device is starting to wake up while auth method is" +
-                                                " none",
-                                )
-                            }
-                            authMethod.isSecure && isUnlocked -> {
-                                switchToScene(
-                                        targetSceneKey = SceneKey.Gone,
-                                        loggingReason =
-                                        "device is starting to wake up while unlocked with a" +
-                                                " secure auth method",
-                                )
-                            }
+            powerInteractor.isAsleep.collect { isAsleep ->
+                if (isAsleep) {
+                    switchToScene(
+                        targetSceneKey = SceneKey.Lockscreen,
+                        loggingReason = "device is starting to sleep",
+                    )
+                } else {
+                    val authMethod = authenticationInteractor.getAuthenticationMethod()
+                    val isUnlocked = deviceEntryInteractor.isUnlocked.value
+                    when {
+                        authMethod == AuthenticationMethodModel.None -> {
+                            switchToScene(
+                                targetSceneKey = SceneKey.Gone,
+                                loggingReason =
+                                    "device is starting to wake up while auth method is" + " none",
+                            )
+                        }
+                        authMethod.isSecure && isUnlocked -> {
+                            switchToScene(
+                                targetSceneKey = SceneKey.Gone,
+                                loggingReason =
+                                    "device is starting to wake up while unlocked with a" +
+                                        " secure auth method",
+                            )
                         }
                     }
                 }
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
index 4bc93a8..2e45353 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
@@ -61,12 +61,17 @@
     data class Swipe(
         /** The direction of the swipe. */
         val direction: Direction,
+        /**
+         * The edge from which the swipe originated or `null`, if the swipe didn't start close to an
+         * edge.
+         */
+        val fromEdge: Edge? = null,
         /** The number of pointers that were used (for example, one or two fingers). */
         val pointerCount: Int = 1,
     ) : UserAction
 
     /** The user has hit the back button or performed the back navigation gesture. */
-    object Back : UserAction
+    data object Back : UserAction
 }
 
 /** Enumerates all known "cardinal" directions for user actions. */
@@ -76,3 +81,11 @@
     RIGHT,
     DOWN,
 }
+
+/** Enumerates all known edges from which a swipe can start. */
+enum class Edge {
+    LEFT,
+    TOP,
+    RIGHT,
+    BOTTOM,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 2f87301..393a698 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -132,6 +132,7 @@
         setUserIdInternal(startingUser)
 
         val filter = IntentFilter().apply {
+            addAction(Intent.ACTION_LOCALE_CHANGED)
             addAction(Intent.ACTION_USER_INFO_CHANGED)
             // These get called when a managed profile goes in or out of quiet mode.
             addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
@@ -149,6 +150,7 @@
 
     override fun onReceive(context: Context, intent: Intent) {
         when (intent.action) {
+            Intent.ACTION_LOCALE_CHANGED,
             Intent.ACTION_USER_INFO_CHANGED,
             Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
             Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
index 9235fcc..c42fdf8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
@@ -67,8 +67,6 @@
         mDebugPaint.setStrokeWidth(2);
         mDebugPaint.setStyle(Paint.Style.STROKE);
         mDebugPaint.setTextSize(24);
-        String headerDebugInfo = mNotificationPanelViewController.getHeaderDebugInfo();
-        if (headerDebugInfo != null) canvas.drawText(headerDebugInfo, 50, 100, mDebugPaint);
 
         drawDebugInfo(canvas, mNotificationPanelViewController.getMaxPanelHeight(),
                 Color.RED, "getMaxPanelHeight()");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index d3d38e5c..ba0cf08 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -138,7 +138,6 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.model.TransitionState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
-import com.android.systemui.power.shared.model.WakefulnessModel;
 import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder;
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
 import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel;
@@ -162,9 +161,10 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.power.shared.model.WakefulnessModel;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.data.repository.ShadeRepository;
-import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
@@ -200,7 +200,6 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
@@ -217,6 +216,7 @@
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
@@ -230,6 +230,8 @@
 import com.android.systemui.util.time.SystemClock;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import kotlin.Unit;
 
 import java.io.PrintWriter;
@@ -362,7 +364,7 @@
     private boolean mIsLaunchAnimationRunning;
     private float mOverExpansion;
     private CentralSurfaces mCentralSurfaces;
-    private HeadsUpManagerPhone mHeadsUpManager;
+    private HeadsUpManager mHeadsUpManager;
     private float mExpandedHeight = 0;
     /** The current squish amount for the predictive back animation */
     private float mCurrentBackProgress = 0.0f;
@@ -1275,7 +1277,8 @@
             KeyguardStatusView keyguardStatusView = mView.getRootView().findViewById(
                     R.id.keyguard_status_view);
             KeyguardStatusViewComponent statusViewComponent =
-                    mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
+                    mKeyguardStatusViewComponentFactory.build(keyguardStatusView,
+                            mView.getContext().getDisplay());
             mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
             mKeyguardStatusViewController.init();
         }
@@ -3025,7 +3028,7 @@
         return headsUpVisible || isExpanded() || mBouncerShowing;
     }
 
-    private void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
+    private void setHeadsUpManager(HeadsUpManager headsUpManager) {
         mHeadsUpManager = headsUpManager;
         mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
         mHeadsUpTouchHelper = new HeadsUpTouchHelper(
@@ -3378,6 +3381,7 @@
         mBlockingExpansionForCurrentTouch = isTracking();
     }
 
+    @NeverCompile
     @Override
     public void dump(PrintWriter pw, String[] args) {
         pw.println(TAG + ":");
@@ -3507,7 +3511,7 @@
             GestureRecorder recorder,
             Runnable hideExpandedRunnable,
             NotificationShelfController notificationShelfController,
-            HeadsUpManagerPhone headsUpManager) {
+            HeadsUpManager headsUpManager) {
         setHeadsUpManager(headsUpManager);
         // TODO(b/254859580): this can be injected.
         mCentralSurfaces = centralSurfaces;
@@ -3556,10 +3560,6 @@
         mView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
     }
 
-    String getHeaderDebugInfo() {
-        return "USER " + mHeadsUpManager.getUser();
-    }
-
     @Override
     public void onThemeChanged() {
         mConfigurationListener.onThemeChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 6cf4ff5..d05dfe2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -21,7 +21,6 @@
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.app.StatusBarManager;
-import android.os.PowerManager;
 import android.util.Log;
 import android.view.GestureDetector;
 import android.view.InputDevice;
@@ -36,10 +35,11 @@
 import com.android.keyguard.LockIconViewController;
 import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.back.domain.interactor.BackActionInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
 import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel;
 import com.android.systemui.classifier.FalsingCollector;
@@ -48,7 +48,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor;
+import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.model.TransitionState;
@@ -56,6 +56,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
 import com.android.systemui.log.BouncerLogger;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.res.R;
 import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -105,7 +106,9 @@
     private final NotificationInsetsController mNotificationInsetsController;
     private final boolean mIsTrackpadCommonEnabled;
     private final FeatureFlags mFeatureFlags;
-    private final KeyEventInteractor mKeyEventInteractor;
+    private final SysUIKeyEventHandler mSysUIKeyEventHandler;
+    private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+    private final AlternateBouncerInteractor mAlternateBouncerInteractor;
     private GestureDetector mPulsingWakeupGestureHandler;
     private GestureDetector mDreamingWakeupGestureHandler;
     private View mBrightnessMirror;
@@ -182,7 +185,9 @@
             SystemClock clock,
             BouncerMessageInteractor bouncerMessageInteractor,
             BouncerLogger bouncerLogger,
-            KeyEventInteractor keyEventInteractor) {
+            SysUIKeyEventHandler sysUIKeyEventHandler,
+            PrimaryBouncerInteractor primaryBouncerInteractor,
+            AlternateBouncerInteractor alternateBouncerInteractor) {
         mLockscreenShadeTransitionController = transitionController;
         mFalsingCollector = falsingCollector;
         mStatusBarStateController = statusBarStateController;
@@ -209,7 +214,9 @@
         mNotificationInsetsController = notificationInsetsController;
         mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
         mFeatureFlags = featureFlags;
-        mKeyEventInteractor = keyEventInteractor;
+        mSysUIKeyEventHandler = sysUIKeyEventHandler;
+        mPrimaryBouncerInteractor = primaryBouncerInteractor;
+        mAlternateBouncerInteractor = alternateBouncerInteractor;
 
         // This view is not part of the newly inflated expanded status bar.
         mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -351,16 +358,6 @@
                 if (mStatusBarStateController.isDozing()) {
                     mDozeScrimController.extendPulse();
                 }
-                mLockIconViewController.onTouchEvent(
-                        ev,
-                        /* onGestureDetectedRunnable */
-                        () -> {
-                            mService.userActivity();
-                            mPowerInteractor.wakeUpIfDozing(
-                                    "LOCK_ICON_TOUCH",
-                                    PowerManager.WAKE_REASON_GESTURE);
-                        }
-                );
 
                 // In case we start outside of the view bounds (below the status bar), we need to
                 // dispatch the touch manually as the view system can't accommodate for touches
@@ -415,8 +412,18 @@
 
             private boolean shouldInterceptTouchEventInternal(MotionEvent ev) {
                 mLastInterceptWasDragDownHelper = false;
-                if (mStatusBarStateController.isDozing() && !mDozeServiceHost.isPulsing()
-                        && !mDockManager.isDocked()) {
+                // When the device starts dozing, there's a delay before the device's display state
+                // changes from ON => DOZE to allow for the light reveal animation to run at
+                // a higher refresh rate and to delay visual changes (ie: display blink) when
+                // changing the display state. We'll call this specific state the
+                // "aodDefermentState". In this state we:
+                //     - don't want touches to get sent to underlying views, except the lock icon
+                //     - handle the tap to wake gesture via the PulsingGestureListener
+                if (mStatusBarStateController.isDozing()
+                        && !mDozeServiceHost.isPulsing()
+                        && !mDockManager.isDocked()
+                        && !mLockIconViewController.willHandleTouchWhileDozing(ev)
+                ) {
                     if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                         mShadeLogger.d("NSWVC: capture all touch events in always-on");
                     }
@@ -432,16 +439,15 @@
                     return true;
                 }
 
-                if (mLockIconViewController.onInterceptTouchEvent(ev)) {
-                    // immediately return true; don't send the touch to the drag down helper
-                    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-                        mShadeLogger.d("NSWVC: don't send touch to drag down helper");
-                    }
-                    return true;
+                boolean bouncerShowing;
+                if (mFeatureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+                    bouncerShowing = mPrimaryBouncerInteractor.isBouncerShowing()
+                            || mAlternateBouncerInteractor.isVisibleState();
+                } else {
+                    bouncerShowing = mService.isBouncerShowing();
                 }
-
                 if (mNotificationPanelViewController.isFullyExpanded()
-                        && !mService.isBouncerShowing()
+                        && !bouncerShowing
                         && !mStatusBarStateController.isDozing()) {
                     if (mDragDownHelper.isDragDownEnabled()) {
                         // This handles drag down over lockscreen
@@ -523,17 +529,17 @@
 
             @Override
             public boolean interceptMediaKey(KeyEvent event) {
-                return mKeyEventInteractor.interceptMediaKey(event);
+                return mSysUIKeyEventHandler.interceptMediaKey(event);
             }
 
             @Override
             public boolean dispatchKeyEventPreIme(KeyEvent event) {
-                return mKeyEventInteractor.dispatchKeyEventPreIme(event);
+                return mSysUIKeyEventHandler.dispatchKeyEventPreIme(event);
             }
 
             @Override
             public boolean dispatchKeyEvent(KeyEvent event) {
-                return mKeyEventInteractor.dispatchKeyEvent(event);
+                return mSysUIKeyEventHandler.dispatchKeyEvent(event);
             }
         });
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index 9b74ac4..3bbb2cf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -105,6 +105,8 @@
 import com.android.systemui.util.LargeScreenUtils;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import dagger.Lazy;
 
 import java.io.PrintWriter;
@@ -2015,6 +2017,7 @@
                 (int) ((y - getInitialTouchY()) / displayDensity), (int) (vel / displayDensity));
     }
 
+    @NeverCompile
     @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println(TAG + ":");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index 447a15d..2c4b0b9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -178,9 +178,6 @@
 
     /** Listens for shade visibility changes. */
     interface ShadeVisibilityListener {
-        /** Called when the visibility of the shade changes. */
-        void visibilityChanged(boolean visible);
-
         /** Called when shade expanded and visible state changed. */
         void expandedVisibleChanged(boolean expandedVisible);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 367449b..fdc7eec 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -24,6 +24,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
+import com.android.systemui.DejankUtils;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -75,6 +76,7 @@
     private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
 
     private boolean mExpandedVisible;
+    private boolean mLockscreenOrShadeVisible;
 
     private NotificationPresenter mPresenter;
     private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
@@ -399,8 +401,19 @@
     }
 
     private void notifyVisibilityChanged(boolean visible) {
-        mShadeVisibilityListener.visibilityChanged(visible);
         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(visible);
+        if (mLockscreenOrShadeVisible != visible) {
+            mLockscreenOrShadeVisible = visible;
+            if (visible) {
+                // It would be best if this could be done as a side effect of listening to the
+                // [WindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible] flow inside
+                // NotificationShadeWindowViewController. However, there's no guarantee that the
+                // flow will emit in the same frame as when the visibility changed, and we want the
+                // DejankUtils to be notified immediately, so we do it immediately here.
+                DejankUtils.notifyRendererOfExpensiveFrame(
+                        getNotificationShadeWindowView(), "onShadeVisibilityChanged");
+            }
+        }
     }
 
     private void notifyExpandedVisibleChanged(boolean expandedVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index 6ee6cbf..4e23e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -20,7 +20,7 @@
 import com.android.systemui.statusbar.NotificationShelfController
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.HeadsUpManager
 
 /**
  * Allows CentralSurfacesImpl to interact with the shade. Only CentralSurfacesImpl should reference
@@ -34,7 +34,7 @@
         recorder: GestureRecorder,
         hideExpandedRunnable: Runnable,
         notificationShelfController: NotificationShelfController,
-        headsUpManager: HeadsUpManagerPhone
+        headsUpManager: HeadsUpManager
     )
 
     /** Cancels any pending collapses. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index ac8333a..e487a6f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -19,7 +19,11 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.ObservableTransitionState
@@ -27,8 +31,9 @@
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepository
 import com.android.systemui.user.domain.interactor.UserInteractor
 import com.android.systemui.util.kotlin.pairwise
 import javax.inject.Inject
@@ -56,13 +61,16 @@
 @Inject
 constructor(
     @Application scope: CoroutineScope,
+    deviceProvisioningRepository: DeviceProvisioningRepository,
     disableFlagsRepository: DisableFlagsRepository,
+    dozeParams: DozeParameters,
     sceneContainerFlags: SceneContainerFlags,
     // TODO(b/300258424) convert to direct reference instead of provider
     sceneInteractorProvider: Provider<SceneInteractor>,
     keyguardRepository: KeyguardRepository,
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
+    powerInteractor: PowerInteractor,
     userSetupRepository: UserSetupRepository,
-    deviceProvisionedController: DeviceProvisionedController,
     userInteractor: UserInteractor,
     sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
     repository: ShadeRepository,
@@ -187,6 +195,26 @@
         combine(isUserInteractingWithShade, isUserInteractingWithShade) { shade, qs -> shade || qs }
             .distinctUntilChanged()
 
+    /** Are touches allowed on the notification panel? */
+    val isShadeTouchable: Flow<Boolean> =
+        combine(
+            powerInteractor.isAsleep,
+            keyguardTransitionInteractor.isInTransitionToStateWhere { it == KeyguardState.AOD },
+            keyguardRepository.dozeTransitionModel.map { it.to == DozeStateModel.DOZE_PULSING },
+            deviceProvisioningRepository.isFactoryResetProtectionActive,
+        ) { isAsleep, goingToSleep, isPulsing, isFrpActive ->
+            when {
+                // Touches are disabled when Factory Reset Protection is active
+                isFrpActive -> false
+                // If the device is going to sleep, only accept touches if we're still
+                // animating
+                goingToSleep -> dozeParams.shouldControlScreenOff()
+                // If the device is asleep, only accept touches if there's a pulse
+                isAsleep -> isPulsing
+                else -> true
+            }
+        }
+
     /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
     val isExpandToQsEnabled: Flow<Boolean> =
         combine(
@@ -194,8 +222,9 @@
             isShadeEnabled,
             keyguardRepository.isDozing,
             userSetupRepository.isUserSetupFlow,
-        ) { disableFlags, isShadeEnabled, isDozing, isUserSetup ->
-            deviceProvisionedController.isDeviceProvisioned &&
+            deviceProvisioningRepository.isDeviceProvisioned,
+        ) { disableFlags, isShadeEnabled, isDozing, isUserSetup, isDeviceProvisioned ->
+            isDeviceProvisioned &&
                 // Disallow QS during setup if it's a simple user switcher. (The user intends to
                 // use the lock screen user switcher, QS is not needed.)
                 (isUserSetup || !userInteractor.isSimpleUserSwitcher) &&
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index d24f9d8..77b0958 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -18,6 +18,8 @@
 
 import android.view.View;
 
+import androidx.annotation.Nullable;
+
 import com.android.app.animation.Interpolators;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -113,7 +115,16 @@
         fadeIn(view, ANIMATION_DURATION_LENGTH, 0);
     }
 
+    public static void fadeIn(final View view, Runnable endRunnable) {
+        fadeIn(view, ANIMATION_DURATION_LENGTH, /* delay= */ 0, endRunnable);
+    }
+
     public static void fadeIn(final View view, long duration, int delay) {
+        fadeIn(view, duration, delay, /* endRunnable= */ null);
+    }
+
+    public static void fadeIn(final View view, long duration, int delay,
+            @Nullable Runnable endRunnable) {
         view.animate().cancel();
         if (view.getVisibility() == View.INVISIBLE) {
             view.setAlpha(0.0f);
@@ -124,7 +135,7 @@
                 .setDuration(duration)
                 .setStartDelay(delay)
                 .setInterpolator(Interpolators.ALPHA_IN)
-                .withEndAction(null);
+                .withEndAction(endRunnable);
         if (view.hasOverlappingRendering() && view.getLayerType() != View.LAYER_TYPE_HARDWARE) {
             view.animate().withLayer();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 09ad55e..f8c049e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -37,11 +37,11 @@
 import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.SystemBarUtils;
-import com.android.systemui.res.R;
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.flags.ViewRefactorFlag;
+import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.SourceType;
@@ -96,10 +96,10 @@
     private float mCornerAnimationDistance;
     private NotificationShelfController mController;
     private float mActualWidth = -1;
-    private final ViewRefactorFlag mSensitiveRevealAnim =
-            new ViewRefactorFlag(Flags.SENSITIVE_REVEAL_ANIM);
-    private final ViewRefactorFlag mShelfRefactor =
-            new ViewRefactorFlag(Flags.NOTIFICATION_SHELF_REFACTOR);
+    private final RefactorFlag mSensitiveRevealAnim =
+            RefactorFlag.forView(Flags.SENSITIVE_REVEAL_ANIM);
+    private final RefactorFlag mShelfRefactor =
+            RefactorFlag.forView(Flags.NOTIFICATION_SHELF_REFACTOR);
     private boolean mCanModifyColorOfNotifications;
     private boolean mCanInteract;
     private NotificationStackScrollLayout mHostLayout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 3640ae0..4ea7026 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -31,22 +31,22 @@
 import com.android.app.animation.Interpolators
 import com.android.systemui.Dumpable
 import com.android.systemui.Gefingerpoken
-import com.android.systemui.res.R
 import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import java.io.PrintWriter
 import javax.inject.Inject
 import kotlin.math.max
@@ -63,7 +63,7 @@
     context: Context,
     private val wakeUpCoordinator: NotificationWakeUpCoordinator,
     private val bypassController: KeyguardBypassController,
-    private val headsUpManager: HeadsUpManagerPhone,
+    private val headsUpManager: HeadsUpManager,
     private val roundnessManager: NotificationRoundnessManager,
     configurationController: ConfigurationController,
     private val statusBarStateController: StatusBarStateController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index f616b91..3a4ad0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -51,6 +51,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.Interpolator;
 
+import androidx.annotation.Nullable;
 import androidx.core.graphics.ColorUtils;
 
 import com.android.app.animation.Interpolators;
@@ -959,12 +960,17 @@
     }
 
     public void setDozing(boolean dozing, boolean fade, long delay) {
+        setDozing(dozing, fade, delay, /* onChildCompleted= */ null);
+    }
+
+    public void setDozing(boolean dozing, boolean fade, long delay,
+            @Nullable Runnable endRunnable) {
         mDozer.setDozing(f -> {
             mDozeAmount = f;
             updateDecorColor();
             updateIconColor();
             updateAllowAnimation();
-        }, dozing, fade, delay, this);
+        }, dozing, fade, delay, this, endRunnable);
     }
 
     private void updateAllowAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
index ff40f70..91ca148 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
@@ -87,7 +87,7 @@
      */
     public void init() {
         if (mWifiPickerTracker == null) {
-            mWifiPickerTracker = mWifiPickerTrackerFactory.create(this.getLifecycle(), this);
+            mWifiPickerTracker = mWifiPickerTrackerFactory.create(this.getLifecycle(), this, TAG);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 9db61c6..fc84973 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -83,6 +83,8 @@
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.util.CarrierConfigTracker;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -1154,6 +1156,7 @@
     }
 
     /** */
+    @NeverCompile
     public void dump(PrintWriter pw, String[] args) {
         pw.println("NetworkController state:");
         pw.println("  mUserSetup=" + mUserSetup);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiPickerTrackerFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiPickerTrackerFactory.kt
index ddbfcef..dc2ebe5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiPickerTrackerFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiPickerTrackerFactory.kt
@@ -23,8 +23,8 @@
 import android.os.SimpleClock
 import androidx.lifecycle.Lifecycle
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.concurrency.ThreadFactory
 import com.android.systemui.util.time.SystemClock
 import com.android.wifitrackerlib.WifiPickerTracker
 import com.android.wifitrackerlib.WifiPickerTracker.WifiPickerTrackerCallback
@@ -46,7 +46,7 @@
     private val connectivityManager: ConnectivityManager,
     private val systemClock: SystemClock,
     @Main private val mainHandler: Handler,
-    @Background private val workerHandler: Handler,
+    private val threadFactory: ThreadFactory,
 ) {
     private val clock: Clock =
         object : SimpleClock(ZoneOffset.UTC) {
@@ -60,11 +60,13 @@
     /**
      * Creates a [WifiPickerTracker] instance.
      *
+     * @param name a name to identify the worker thread used for [WifiPickerTracker] operations.
      * @return a new [WifiPickerTracker] or null if [WifiManager] is null.
      */
     fun create(
         lifecycle: Lifecycle,
         listener: WifiPickerTrackerCallback,
+        name: String,
     ): WifiPickerTracker? {
         return if (wifiManager == null) {
             null
@@ -75,7 +77,10 @@
                 wifiManager,
                 connectivityManager,
                 mainHandler,
-                workerHandler,
+                // WifiPickerTracker can take tens of seconds to finish operations, so it can't use
+                // the default background handler (it would block all other background operations).
+                // Use a custom handler instead.
+                threadFactory.buildHandlerOnNewThread("WifiPickerTracker-$name"),
                 clock,
                 MAX_SCAN_AGE_MILLIS,
                 SCAN_INTERVAL_MILLIS,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index 249c831..e2de37f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -18,6 +18,8 @@
 
 import com.android.systemui.CoreStartable
 import com.android.systemui.statusbar.core.StatusBarInitializer
+import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepository
+import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryImpl
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepository
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryImpl
 import com.android.systemui.statusbar.phone.LightBarController
@@ -49,6 +51,11 @@
     abstract fun bindStatusBarModeRepositoryStart(impl: StatusBarModeRepositoryImpl): CoreStartable
 
     @Binds
+    abstract fun bindKeyguardStatusBarRepository(
+        impl: KeyguardStatusBarRepositoryImpl
+    ): KeyguardStatusBarRepository
+
+    @Binds
     @IntoMap
     @ClassKey(OngoingCallController::class)
     abstract fun bindOngoingCallController(impl: OngoingCallController): CoreStartable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
new file mode 100644
index 0000000..8136de9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 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.statusbar.data.repository
+
+import android.content.Context
+import com.android.internal.R
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.user.data.repository.UserSwitcherRepository
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/**
+ * Repository for data that's specific to the status bar **on keyguard**. For data that applies to
+ * all status bars, use [StatusBarModeRepository].
+ */
+interface KeyguardStatusBarRepository {
+    /** True if we can show the user switcher on keyguard and false otherwise. */
+    val isKeyguardUserSwitcherEnabled: Flow<Boolean>
+}
+
+@SysUISingleton
+class KeyguardStatusBarRepositoryImpl
+@Inject
+constructor(
+    context: Context,
+    configurationController: ConfigurationController,
+    userSwitcherRepository: UserSwitcherRepository,
+) : KeyguardStatusBarRepository {
+    private val relevantConfigChanges: Flow<Unit> =
+        ConflatedCallbackFlow.conflatedCallbackFlow {
+            val callback =
+                object : ConfigurationController.ConfigurationListener {
+                    override fun onSmallestScreenWidthChanged() {
+                        trySend(Unit)
+                    }
+
+                    override fun onDensityOrFontScaleChanged() {
+                        trySend(Unit)
+                    }
+                }
+            configurationController.addCallback(callback)
+            awaitClose { configurationController.removeCallback(callback) }
+        }
+
+    private val isKeyguardUserSwitcherConfigEnabled: Flow<Boolean> =
+        // The config depends on screen size and user enabled settings, so re-fetch whenever any of
+        // those change.
+        merge(userSwitcherRepository.isEnabled.map {}, relevantConfigChanges).map {
+            context.resources.getBoolean(R.bool.config_keyguardUserSwitcher)
+        }
+
+    /** True if we can show the user switcher on keyguard and false otherwise. */
+    override val isKeyguardUserSwitcherEnabled: Flow<Boolean> =
+        combine(
+            userSwitcherRepository.isEnabled,
+            isKeyguardUserSwitcherConfigEnabled,
+        ) { isEnabled, isKeyguardEnabled ->
+            isEnabled && isKeyguardEnabled
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/KeyguardStatusBarInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/KeyguardStatusBarInteractor.kt
new file mode 100644
index 0000000..e0c30e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/KeyguardStatusBarInteractor.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.statusbar.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class KeyguardStatusBarInteractor
+@Inject
+constructor(
+    keyguardStatusBarRepository: KeyguardStatusBarRepository,
+) {
+    /** True if we can show the user switcher on keyguard and false otherwise. */
+    val isKeyguardUserSwitcherEnabled: Flow<Boolean> =
+        keyguardStatusBarRepository.isKeyguardUserSwitcherEnabled
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
index 167efc7..dc0eb7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -24,6 +24,8 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import androidx.annotation.Nullable;
+
 import com.android.app.animation.Interpolators;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -81,6 +83,11 @@
 
     public void setDozing(Consumer<Float> listener, boolean dozing,
             boolean animate, long delay, View view) {
+        setDozing(listener, dozing, animate, delay, view, /* endRunnable= */ null);
+    }
+
+    public void setDozing(Consumer<Float> listener, boolean dozing,
+            boolean animate, long delay, View view, @Nullable Runnable endRunnable) {
         if (animate) {
             startIntensityAnimation(a -> listener.accept((Float) a.getAnimatedValue()), dozing,
                     delay,
@@ -89,6 +96,9 @@
                         @Override
                         public void onAnimationEnd(Animator animation) {
                             view.setTag(DOZE_ANIMATOR_TAG, null);
+                            if (endRunnable != null) {
+                                endRunnable.run();
+                            }
                         }
 
                         @Override
@@ -102,6 +112,9 @@
                 animator.cancel();
             }
             listener.accept(dozing ? 1f : 0f);
+            if (endRunnable != null) {
+                endRunnable.run();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index c62546f..756151b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -24,7 +24,7 @@
 import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.HeadsUpUtil
 import kotlin.math.ceil
 import kotlin.math.max
@@ -35,7 +35,7 @@
 class NotificationLaunchAnimatorControllerProvider(
     private val notificationExpansionRepository: NotificationExpansionRepository,
     private val notificationListContainer: NotificationListContainer,
-    private val headsUpManager: HeadsUpManagerPhone,
+    private val headsUpManager: HeadsUpManager,
     private val jankMonitor: InteractionJankMonitor
 ) {
     @JvmOverloads
@@ -62,7 +62,7 @@
 class NotificationLaunchAnimatorController(
     private val notificationExpansionRepository: NotificationExpansionRepository,
     private val notificationListContainer: NotificationListContainer,
-    private val headsUpManager: HeadsUpManagerPhone,
+    private val headsUpManager: HeadsUpManager,
     private val notification: ExpandableNotificationRow,
     private val jankMonitor: InteractionJankMonitor,
     private val onFinishAnimationCallback: Runnable?
@@ -152,16 +152,17 @@
         }
     }
 
-    private val headsUpNotificationRow: ExpandableNotificationRow? get() {
-        val summaryEntry = notificationEntry.parent?.summary
+    private val headsUpNotificationRow: ExpandableNotificationRow?
+        get() {
+            val summaryEntry = notificationEntry.parent?.summary
 
-        return when {
-            headsUpManager.isAlerting(notificationKey) -> notification
-            summaryEntry == null -> null
-            headsUpManager.isAlerting(summaryEntry.key) -> summaryEntry.row
-            else -> null
+            return when {
+                headsUpManager.isAlerting(notificationKey) -> notification
+                summaryEntry == null -> null
+                headsUpManager.isAlerting(summaryEntry.key) -> summaryEntry.row
+                else -> null
+            }
         }
-    }
 
     private fun removeHun(animate: Boolean) {
         val row = headsUpNotificationRow ?: return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
index 328a741..3e9c6fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
@@ -3,10 +3,10 @@
 import android.util.FloatProperty
 import android.view.View
 import androidx.annotation.FloatRange
-import com.android.systemui.res.R
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
-import com.android.systemui.flags.ViewRefactorFlag
+import com.android.systemui.flags.RefactorFlag
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.notification.stack.AnimationProperties
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import kotlin.math.abs
@@ -323,7 +323,7 @@
     internal var maxRadius = maxRadius
         private set
 
-    internal val newHeadsUpAnim = ViewRefactorFlag(featureFlags, Flags.IMPROVED_HUN_ANIMATIONS)
+    internal val newHeadsUpAnim = RefactorFlag.forView(Flags.IMPROVED_HUN_ANIMATIONS, featureFlags)
 
     /** Animatable for top roundness */
     private val topAnimatable = topAnimatable(roundable)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 07eb8a00..2d83970 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -37,8 +37,8 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.headsUpEvents
 import com.android.systemui.util.asIndenting
@@ -85,7 +85,7 @@
     @Application private val scope: CoroutineScope,
     private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
     private val secureSettings: SecureSettings,
-    private val seenNotifsProvider: SeenNotificationsProviderImpl,
+    private val notificationListInteractor: NotificationListInteractor,
     private val statusBarStateController: StatusBarStateController,
 ) : Coordinator, Dumpable {
 
@@ -351,7 +351,7 @@
 
             override fun onCleanup() {
                 logger.logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs)
-                seenNotifsProvider.hasFilteredOutSeenNotifications = hasFilteredAnyNotifs
+                notificationListInteractor.setHasFilteredOutSeenNotifications(hasFilteredAnyNotifs)
                 hasFilteredAnyNotifs = false
             }
         }
@@ -388,8 +388,8 @@
     override fun dump(pw: PrintWriter, args: Array<out String>) =
         with(pw.asIndenting()) {
             println(
-                "seenNotifsProvider.hasFilteredOutSeenNotifications=" +
-                    seenNotifsProvider.hasFilteredOutSeenNotifications
+                "notificationListInteractor.hasFilteredOutSeenNotifications.value=" +
+                    notificationListInteractor.hasFilteredOutSeenNotifications.value
             )
             println("unseen notifications:")
             indentIfPossible {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index 657c394d..c0f674846 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.Compile
+import com.android.systemui.util.traceSection
 import javax.inject.Inject
 
 /**
@@ -122,8 +123,10 @@
 
     private fun updateNotificationsOnUiModeChanged() {
         log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" }
-        mPipeline?.allNotifs?.forEach { entry ->
-            entry.row?.onUiModeChanged()
+        traceSection("updateNotifOnUiModeChanged") {
+            mPipeline?.allNotifs?.forEach { entry ->
+                entry.row?.onUiModeChanged()
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt
deleted file mode 100644
index cff47e2..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.provider
-
-import com.android.systemui.dagger.SysUISingleton
-import dagger.Binds
-import dagger.Module
-import javax.inject.Inject
-
-/** Keeps track of whether "seen" notification content has been filtered out of the shade. */
-interface SeenNotificationsProvider {
-    /** Are any already-seen notifications currently filtered out of the shade? */
-    val hasFilteredOutSeenNotifications: Boolean
-}
-
-@Module
-interface SeenNotificationsProviderModule {
-    @Binds
-    fun bindSeenNotificationsProvider(
-        impl: SeenNotificationsProviderImpl
-    ): SeenNotificationsProvider
-}
-
-@SysUISingleton
-class SeenNotificationsProviderImpl @Inject constructor() : SeenNotificationsProvider {
-    override var hasFilteredOutSeenNotifications: Boolean = false
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 59fc387..1a88815 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -231,18 +231,24 @@
     fun getChildCount(): Int = controller.getChildCount()
 
     fun addChildAt(child: ShadeNode, index: Int) {
-        controller.addChildAt(child.controller, index)
-        child.controller.onViewAdded()
+        traceSection("ShadeNode#addChildAt") {
+            controller.addChildAt(child.controller, index)
+            child.controller.onViewAdded()
+        }
     }
 
     fun moveChildTo(child: ShadeNode, index: Int) {
-        controller.moveChildTo(child.controller, index)
-        child.controller.onViewMoved()
+        traceSection("ShadeNode#moveChildTo") {
+            controller.moveChildTo(child.controller, index)
+            child.controller.onViewMoved()
+        }
     }
 
     fun removeChild(child: ShadeNode, isTransfer: Boolean) {
-        controller.removeChild(child.controller, isTransfer)
-        child.controller.onViewRemoved()
+        traceSection("ShadeNode#removeChild") {
+            controller.removeChild(child.controller, isTransfer)
+            child.controller.onViewRemoved()
+        }
     }
 
     fun offerToKeepInParentForAnimation(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 8ee0de6..8561869 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -20,10 +20,10 @@
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.shade.ShadeEventsModule;
 import com.android.systemui.statusbar.NotificationListener;
@@ -45,7 +45,6 @@
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProviderImpl;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationVisibilityProviderImpl;
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderModule;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
@@ -54,6 +53,7 @@
 import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
 import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.data.NotificationDataLayerModule;
 import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository;
 import com.android.systemui.statusbar.notification.icon.ConversationIconManager;
 import com.android.systemui.statusbar.notification.icon.IconManager;
@@ -74,9 +74,9 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModelModule;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
 import dagger.Binds;
@@ -95,8 +95,8 @@
 @Module(includes = {
         CoordinatorsModule.class,
         KeyguardNotificationVisibilityProviderModule.class,
-        SeenNotificationsProviderModule.class,
         ShadeEventsModule.class,
+        NotificationDataLayerModule.class,
         NotifPipelineChoreographerModule.class,
         NotificationSectionHeadersModule.class,
         NotificationListViewModelModule.class,
@@ -206,7 +206,7 @@
     static NotificationLaunchAnimatorControllerProvider provideNotifLaunchAnimControllerProvider(
             NotificationExpansionRepository notificationExpansionRepository,
             NotificationListContainer notificationListContainer,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             InteractionJankMonitor jankMonitor) {
         return new NotificationLaunchAnimatorControllerProvider(
                 notificationExpansionRepository,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
new file mode 100644
index 0000000..5435fb5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.data
+
+import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardStateRepositoryModule
+import dagger.Module
+
+@Module(includes = [NotificationsKeyguardStateRepositoryModule::class])
+interface NotificationDataLayerModule
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt
new file mode 100644
index 0000000..cf03d1c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.data.repository
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** View-states pertaining to notifications on the keyguard. */
+interface NotificationsKeyguardViewStateRepository {
+    /** Are notifications fully hidden from view? */
+    val areNotificationsFullyHidden: Flow<Boolean>
+
+    /** Is a pulse expansion occurring? */
+    val isPulseExpanding: Flow<Boolean>
+}
+
+@Module
+interface NotificationsKeyguardStateRepositoryModule {
+    @Binds
+    fun bindImpl(
+        impl: NotificationsKeyguardViewStateRepositoryImpl
+    ): NotificationsKeyguardViewStateRepository
+}
+
+@SysUISingleton
+class NotificationsKeyguardViewStateRepositoryImpl
+@Inject
+constructor(
+    wakeUpCoordinator: NotificationWakeUpCoordinator,
+) : NotificationsKeyguardViewStateRepository {
+    override val areNotificationsFullyHidden: Flow<Boolean> = conflatedCallbackFlow {
+        val listener =
+            object : NotificationWakeUpCoordinator.WakeUpListener {
+                override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
+                    trySend(isFullyHidden)
+                }
+            }
+        trySend(wakeUpCoordinator.notificationsFullyHidden)
+        wakeUpCoordinator.addListener(listener)
+        awaitClose { wakeUpCoordinator.removeListener(listener) }
+    }
+
+    override val isPulseExpanding: Flow<Boolean> = conflatedCallbackFlow {
+        val listener =
+            object : NotificationWakeUpCoordinator.WakeUpListener {
+                override fun onPulseExpansionChanged(expandingChanged: Boolean) {
+                    trySend(expandingChanged)
+                }
+            }
+        trySend(wakeUpCoordinator.isPulseExpanding())
+        wakeUpCoordinator.addListener(listener)
+        awaitClose { wakeUpCoordinator.removeListener(listener) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt
new file mode 100644
index 0000000..87b8e55
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.domain.interactor
+
+import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Domain logic pertaining to notifications on the keyguard. */
+class NotificationsKeyguardInteractor
+@Inject
+constructor(
+    repository: NotificationsKeyguardViewStateRepository,
+) {
+    /** Is a pulse expansion occurring? */
+    val isPulseExpanding: Flow<Boolean> = repository.isPulseExpanding
+
+    /** Are notifications fully hidden from view? */
+    val areNotificationsFullyHidden: Flow<Boolean> = repository.areNotificationsFullyHidden
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index 26db5f2..e74b3fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -11,10 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.row;
+package com.android.systemui.statusbar.notification.footer.ui.view;
 
 import static android.graphics.PorterDuff.Mode.SRC_ATOP;
 
@@ -35,6 +35,8 @@
 
 import com.android.settingslib.Utils;
 import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.row.FooterViewButton;
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.ViewState;
 import com.android.systemui.util.DumpUtilsKt;
@@ -93,6 +95,7 @@
         updateColors();
     }
 
+    /** Show a message instead of the footer buttons. */
     public void setFooterLabelVisible(boolean isVisible) {
         if (isVisible) {
             mManageButton.setVisibility(View.GONE);
@@ -105,14 +108,22 @@
         }
     }
 
+    /** Set onClickListener for the manage/history button. */
     public void setManageButtonClickListener(OnClickListener listener) {
         mManageButton.setOnClickListener(listener);
     }
 
+    /** Set onClickListener for the clear all (end) button. */
     public void setClearAllButtonClickListener(OnClickListener listener) {
         mClearAllButton.setOnClickListener(listener);
     }
 
+    /**
+     * Whether the touch is outside the Clear all button.
+     *
+     * TODO(b/293167744): This is an artifact from the time when we could press underneath the
+     * shade to dismiss it. Check if it's safe to remove.
+     */
     public boolean isOnEmptySpace(float touchX, float touchY) {
         return touchX < mContent.getX()
                 || touchX > mContent.getX() + mContent.getWidth()
@@ -120,6 +131,7 @@
                 || touchY > mContent.getY() + mContent.getHeight();
     }
 
+    /** Show "History" instead of "Manage" on the start button. */
     public void showHistory(boolean showHistory) {
         if (mShowHistory == showHistory) {
             return;
@@ -141,6 +153,7 @@
                 .setCompoundDrawablesRelative(mSeenNotifsFilteredIcon, null, null, null);
     }
 
+    /** Whether the start button shows "History" (true) or "Manage" (false). */
     public boolean isHistoryShown() {
         return mShowHistory;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
index 20241c3..50efbb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
@@ -26,25 +26,21 @@
 import androidx.annotation.ColorInt
 import androidx.annotation.VisibleForTesting
 import androidx.collection.ArrayMap
-import com.android.app.animation.Interpolators
 import com.android.internal.statusbar.StatusBarIcon
 import com.android.internal.util.ContrastColorUtil
 import com.android.settingslib.Utils
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.demomode.DemoMode
 import com.android.systemui.demomode.DemoModeController
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
-import com.android.systemui.flags.ViewRefactorFlag
+import com.android.systemui.flags.RefactorFlag
 import com.android.systemui.plugins.DarkIconDispatcher
-import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.res.R
-import com.android.systemui.statusbar.CrossFadeHelper
 import com.android.systemui.statusbar.NotificationListener
 import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.NotificationShelfController
 import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.NotificationUtils
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -59,6 +55,7 @@
 import com.android.systemui.statusbar.phone.NotificationIconAreaController
 import com.android.systemui.statusbar.phone.NotificationIconContainer
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.wm.shell.bubbles.Bubbles
 import java.util.Optional
@@ -78,9 +75,9 @@
 @Inject
 constructor(
     private val context: Context,
-    private val statusBarStateController: StatusBarStateController,
     private val wakeUpCoordinator: NotificationWakeUpCoordinator,
     private val bypassController: KeyguardBypassController,
+    private val configurationController: ConfigurationController,
     private val mediaManager: NotificationMediaManager,
     notificationListener: NotificationListener,
     private val dozeParameters: DozeParameters,
@@ -88,7 +85,7 @@
     private val bubblesOptional: Optional<Bubbles>,
     demoModeController: DemoModeController,
     darkIconDispatcher: DarkIconDispatcher,
-    featureFlags: FeatureFlags,
+    private val featureFlags: FeatureFlagsClassic,
     private val statusBarWindowController: StatusBarWindowController,
     private val screenOffAnimationController: ScreenOffAnimationController,
     private val shelfIconsViewModel: NotificationIconContainerShelfViewModel,
@@ -97,14 +94,12 @@
 ) :
     NotificationIconAreaController,
     DarkIconDispatcher.DarkReceiver,
-    StatusBarStateController.StateListener,
     NotificationWakeUpCoordinator.WakeUpListener,
     DemoMode {
 
     private val contrastColorUtil: ContrastColorUtil = ContrastColorUtil.getInstance(context)
     private val updateStatusBarIcons = Runnable { updateStatusBarIcons() }
-    private val shelfRefactor = ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR)
-    private val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)
+    private val shelfRefactor = RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR)
     private val tintAreas = ArrayList<Rect>()
 
     private var iconSize = 0
@@ -117,9 +112,7 @@
     private var aodIcons: NotificationIconContainer? = null
     private var aodBindJob: DisposableHandle? = null
     private var aodIconAppearTranslation = 0
-    private var animationsEnabled = false
     private var aodIconTint = 0
-    private var aodIconsVisible = false
     private var showLowPriority = true
 
     @VisibleForTesting
@@ -132,7 +125,6 @@
         }
 
     init {
-        statusBarStateController.addCallback(this)
         wakeUpCoordinator.addListener(this)
         demoModeController.addCallback(this)
         notificationListener.addNotificationSettingsListener(settingsListener)
@@ -156,9 +148,15 @@
         }
         this.aodIcons = aodIcons
         this.aodIcons!!.setOnLockScreen(true)
-        aodBindJob = NotificationIconContainerViewBinder.bind(aodIcons, aodIconsViewModel)
-        updateAodIconsVisibility(animate = false, forceUpdate = changed)
-        updateAnimations()
+        aodBindJob =
+            NotificationIconContainerViewBinder.bind(
+                aodIcons,
+                aodIconsViewModel,
+                configurationController,
+                dozeParameters,
+                featureFlags,
+                screenOffAnimationController,
+            )
         if (changed) {
             updateAodNotificationIcons()
         }
@@ -170,7 +168,14 @@
 
     override fun setShelfIcons(icons: NotificationIconContainer) {
         if (shelfRefactor.expectEnabled()) {
-            NotificationIconContainerViewBinder.bind(icons, shelfIconsViewModel)
+            NotificationIconContainerViewBinder.bind(
+                icons,
+                shelfIconsViewModel,
+                configurationController,
+                dozeParameters,
+                featureFlags,
+                screenOffAnimationController,
+            )
             shelfIcons = icons
         }
     }
@@ -243,23 +248,7 @@
         notificationIcons!!.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate)
     }
 
-    override fun onDozingChanged(isDozing: Boolean) {
-        if (aodIcons == null) {
-            return
-        }
-        val animate = (dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking)
-        aodIcons!!.setDozing(isDozing, animate, 0)
-    }
-
-    override fun setAnimationsEnabled(enabled: Boolean) {
-        animationsEnabled = enabled
-        updateAnimations()
-    }
-
-    override fun onStateChanged(newState: Int) {
-        updateAodIconsVisibility(animate = false, forceUpdate = false)
-        updateAnimations()
-    }
+    override fun setAnimationsEnabled(enabled: Boolean) = unsupported
 
     override fun onThemeChanged() {
         reloadAodColor()
@@ -270,50 +259,11 @@
         return if (aodIcons == null) 0 else aodIcons!!.height
     }
 
-    @VisibleForTesting
-    fun appearAodIcons() {
-        if (aodIcons == null) {
-            return
-        }
-        if (screenOffAnimationController.shouldAnimateAodIcons()) {
-            if (!statusViewMigrated) {
-                aodIcons!!.translationY = -aodIconAppearTranslation.toFloat()
-            }
-            aodIcons!!.alpha = 0f
-            animateInAodIconTranslation()
-            aodIcons!!
-                .animate()
-                .alpha(1f)
-                .setInterpolator(Interpolators.LINEAR)
-                .setDuration(AOD_ICONS_APPEAR_DURATION)
-                .start()
-        } else {
-            aodIcons!!.alpha = 1.0f
-            if (!statusViewMigrated) {
-                aodIcons!!.translationY = 0f
-            }
-        }
-    }
-
     override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
-        var animate = true
-        if (!bypassController.bypassEnabled) {
-            animate = dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking
-            // We only want the appear animations to happen when the notifications get fully hidden,
-            // since otherwise the unhide animation overlaps
-            animate = animate and isFullyHidden
-        }
-        updateAodIconsVisibility(animate, false /* force */)
         updateAodNotificationIcons()
         updateAodIconColors()
     }
 
-    override fun onPulseExpansionChanged(expandingChanged: Boolean) {
-        if (expandingChanged) {
-            updateAodIconsVisibility(animate = true, forceUpdate = false)
-        }
-    }
-
     override fun demoCommands(): List<String> {
         val commands = ArrayList<String>()
         commands.add(DemoMode.COMMAND_NOTIFICATIONS)
@@ -344,7 +294,14 @@
         val layoutInflater = LayoutInflater.from(context)
         notificationIconArea = inflateIconArea(layoutInflater)
         notificationIcons = notificationIconArea?.findViewById(R.id.notificationIcons)
-        NotificationIconContainerViewBinder.bind(notificationIcons!!, statusBarIconsViewModel)
+        NotificationIconContainerViewBinder.bind(
+            notificationIcons!!,
+            statusBarIconsViewModel,
+            configurationController,
+            dozeParameters,
+            featureFlags,
+            screenOffAnimationController,
+        )
     }
 
     private fun updateIconLayoutParams(context: Context) {
@@ -594,25 +551,6 @@
         v.setDecorColor(tint)
     }
 
-    private fun updateAnimations() {
-        val inShade = statusBarStateController.state == StatusBarState.SHADE
-        if (aodIcons != null) {
-            aodIcons!!.setAnimationsEnabled(animationsEnabled && !inShade)
-        }
-        notificationIcons!!.setAnimationsEnabled(animationsEnabled && inShade)
-    }
-
-    private fun animateInAodIconTranslation() {
-        if (!statusViewMigrated) {
-            aodIcons!!
-                .animate()
-                .setInterpolator(Interpolators.DECELERATE_QUINT)
-                .translationY(0f)
-                .setDuration(AOD_ICONS_APPEAR_DURATION)
-                .start()
-        }
-    }
-
     private fun reloadAodColor() {
         aodIconTint =
             Utils.getColorAttrDefaultColor(
@@ -635,59 +573,13 @@
         }
     }
 
-    private fun updateAodIconsVisibility(animate: Boolean, forceUpdate: Boolean) {
-        if (aodIcons == null) {
-            return
-        }
-        var visible = (bypassController.bypassEnabled || wakeUpCoordinator.notificationsFullyHidden)
-
-        // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off animation is
-        // playing, in which case we want them to be visible since we're animating in the AOD UI and
-        // will be switching to KEYGUARD shortly.
-        if (
-            statusBarStateController.state != StatusBarState.KEYGUARD &&
-                !screenOffAnimationController.shouldShowAodIconsWhenShade()
-        ) {
-            visible = false
-        }
-        if (visible && wakeUpCoordinator.isPulseExpanding() && !bypassController.bypassEnabled) {
-            visible = false
-        }
-        if (aodIconsVisible != visible || forceUpdate) {
-            aodIconsVisible = visible
-            aodIcons!!.animate().cancel()
-            if (animate) {
-                val wasFullyInvisible = aodIcons!!.visibility != View.VISIBLE
-                if (aodIconsVisible) {
-                    if (wasFullyInvisible) {
-                        // No fading here, let's just appear the icons instead!
-                        aodIcons!!.visibility = View.VISIBLE
-                        aodIcons!!.alpha = 1.0f
-                        appearAodIcons()
-                    } else {
-                        // Let's make sure the icon are translated to 0, since we cancelled it above
-                        animateInAodIconTranslation()
-                        // We were fading out, let's fade in instead
-                        CrossFadeHelper.fadeIn(aodIcons)
-                    }
-                } else {
-                    // Let's make sure the icon are translated to 0, since we cancelled it above
-                    animateInAodIconTranslation()
-                    CrossFadeHelper.fadeOut(aodIcons)
-                }
-            } else {
-                aodIcons!!.alpha = 1.0f
-                if (!statusViewMigrated) {
-                    aodIcons!!.translationY = 0f
-                }
-                aodIcons!!.visibility = if (visible) View.VISIBLE else View.INVISIBLE
-            }
-        }
-    }
-
     companion object {
-        private const val AOD_ICONS_APPEAR_DURATION: Long = 200
-
         @ColorInt private val DEFAULT_AOD_ICON_COLOR = -0x1
+
+        val unsupported: Nothing
+            get() =
+                error(
+                    "Code path not supported when NOTIFICATION_ICON_CONTAINER_REFACTOR is disabled"
+                )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index 8293bb3..0d2f00a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -15,19 +15,172 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewbinder
 
+import android.content.res.Resources
+import android.view.View
+import androidx.annotation.DimenRes
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.CrossFadeHelper
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel
+import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.NotificationIconContainer
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged
+import com.android.systemui.util.kotlin.stateFlow
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
 
 /** Binds a [NotificationIconContainer] to its [view model][NotificationIconContainerViewModel]. */
 object NotificationIconContainerViewBinder {
     fun bind(
         view: NotificationIconContainer,
         viewModel: NotificationIconContainerViewModel,
+        configurationController: ConfigurationController,
+        dozeParameters: DozeParameters,
+        featureFlags: FeatureFlagsClassic,
+        screenOffAnimationController: ScreenOffAnimationController,
     ): DisposableHandle {
-        return view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) {} }
+        return view.repeatWhenAttached {
+            repeatOnLifecycle(Lifecycle.State.CREATED) {
+                launch { viewModel.animationsEnabled.collect(view::setAnimationsEnabled) }
+                launch {
+                    viewModel.isDozing.collect { (isDozing, animate) ->
+                        val animateIfNotBlanking = animate && !dozeParameters.displayNeedsBlanking
+                        view.setDozing(isDozing, animateIfNotBlanking, /* delay= */ 0) {
+                            viewModel.completeDozeAnimation()
+                        }
+                    }
+                }
+                // TODO(278765923): this should live where AOD is bound, not inside of the NIC
+                //  view-binder
+                launch {
+                    val iconAppearTranslation =
+                        view.resources.getConfigAwareDimensionPixelSize(
+                            this,
+                            configurationController,
+                            R.dimen.shelf_appear_translation,
+                        )
+                    bindVisibility(
+                        viewModel,
+                        view,
+                        featureFlags,
+                        screenOffAnimationController,
+                        iconAppearTranslation,
+                    ) {
+                        viewModel.completeVisibilityAnimation()
+                    }
+                }
+            }
+        }
     }
+    private suspend fun bindVisibility(
+        viewModel: NotificationIconContainerViewModel,
+        view: NotificationIconContainer,
+        featureFlags: FeatureFlagsClassic,
+        screenOffAnimationController: ScreenOffAnimationController,
+        iconAppearTranslation: StateFlow<Int>,
+        onAnimationEnd: () -> Unit,
+    ) {
+        val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)
+        viewModel.isVisible.collect { (isVisible, animate) ->
+            view.animate().cancel()
+            when {
+                !animate -> {
+                    view.alpha = 1f
+                    if (!statusViewMigrated) {
+                        view.translationY = 0f
+                    }
+                    view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
+                }
+                featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> {
+                    animateInIconTranslation(view, statusViewMigrated)
+                    if (isVisible) {
+                        CrossFadeHelper.fadeIn(view, onAnimationEnd)
+                    } else {
+                        CrossFadeHelper.fadeOut(view, onAnimationEnd)
+                    }
+                }
+                !isVisible -> {
+                    // Let's make sure the icon are translated to 0, since we cancelled it above
+                    animateInIconTranslation(view, statusViewMigrated)
+                    CrossFadeHelper.fadeOut(view, onAnimationEnd)
+                }
+                view.visibility != View.VISIBLE -> {
+                    // No fading here, let's just appear the icons instead!
+                    view.visibility = View.VISIBLE
+                    view.alpha = 1f
+                    appearIcons(
+                        view,
+                        animate = screenOffAnimationController.shouldAnimateAodIcons(),
+                        iconAppearTranslation.value,
+                        statusViewMigrated,
+                    )
+                    onAnimationEnd()
+                }
+                else -> {
+                    // Let's make sure the icons are translated to 0, since we cancelled it above
+                    animateInIconTranslation(view, statusViewMigrated)
+                    // We were fading out, let's fade in instead
+                    CrossFadeHelper.fadeIn(view, onAnimationEnd)
+                }
+            }
+        }
+    }
+
+    private fun appearIcons(
+        view: View,
+        animate: Boolean,
+        iconAppearTranslation: Int,
+        statusViewMigrated: Boolean,
+    ) {
+        if (animate) {
+            if (!statusViewMigrated) {
+                view.translationY = -iconAppearTranslation.toFloat()
+            }
+            view.alpha = 0f
+            animateInIconTranslation(view, statusViewMigrated)
+            view
+                .animate()
+                .alpha(1f)
+                .setInterpolator(Interpolators.LINEAR)
+                .setDuration(AOD_ICONS_APPEAR_DURATION)
+                .start()
+        } else {
+            view.alpha = 1.0f
+            if (!statusViewMigrated) {
+                view.translationY = 0f
+            }
+        }
+    }
+
+    private fun animateInIconTranslation(view: View, statusViewMigrated: Boolean) {
+        if (!statusViewMigrated) {
+            view
+                .animate()
+                .setInterpolator(Interpolators.DECELERATE_QUINT)
+                .translationY(0f)
+                .setDuration(AOD_ICONS_APPEAR_DURATION)
+                .start()
+        }
+    }
+
+    private const val AOD_ICONS_APPEAR_DURATION: Long = 200
 }
+
+fun Resources.getConfigAwareDimensionPixelSize(
+    scope: CoroutineScope,
+    configurationController: ConfigurationController,
+    @DimenRes id: Int,
+): StateFlow<Int> =
+    scope.stateFlow(
+        changedSignals = configurationController.onDensityOrFontScaleChanged,
+        getValue = { getDimensionPixelSize(id) }
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
index f68b0ef..3289a3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
@@ -15,8 +15,146 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.util.kotlin.pairwise
+import com.android.systemui.util.kotlin.sample
+import com.android.systemui.util.ui.AnimatableEvent
+import com.android.systemui.util.ui.AnimatedValue
+import com.android.systemui.util.ui.toAnimatedValueFlow
 import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
 
 /** View-model for the row of notification icons displayed on the always-on display. */
-class NotificationIconContainerAlwaysOnDisplayViewModel @Inject constructor() :
-    NotificationIconContainerViewModel
+@SysUISingleton
+class NotificationIconContainerAlwaysOnDisplayViewModel
+@Inject
+constructor(
+    private val deviceEntryInteractor: DeviceEntryInteractor,
+    private val dozeParameters: DozeParameters,
+    private val featureFlags: FeatureFlagsClassic,
+    keyguardInteractor: KeyguardInteractor,
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
+    private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
+    screenOffAnimationController: ScreenOffAnimationController,
+    shadeInteractor: ShadeInteractor,
+) : NotificationIconContainerViewModel {
+
+    private val onDozeAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
+    private val onVisAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
+
+    override val animationsEnabled: Flow<Boolean> =
+        combine(
+            shadeInteractor.isShadeTouchable,
+            keyguardInteractor.isKeyguardVisible,
+        ) { panelTouchesEnabled, isKeyguardVisible ->
+            panelTouchesEnabled && isKeyguardVisible
+        }
+
+    override val isDozing: Flow<AnimatedValue<Boolean>> =
+        keyguardTransitionInteractor.startedKeyguardTransitionStep
+            // Determine if we're dozing based on the most recent transition
+            .map { step: TransitionStep ->
+                val isDozing = step.to == KeyguardState.AOD || step.to == KeyguardState.DOZING
+                isDozing to step
+            }
+            // Only emit changes based on whether we've started or stopped dozing
+            .distinctUntilChanged { (wasDozing, _), (isDozing, _) -> wasDozing != isDozing }
+            // Determine whether we need to animate
+            .map { (isDozing, step) ->
+                val animate = step.to == KeyguardState.AOD || step.from == KeyguardState.AOD
+                AnimatableEvent(isDozing, animate)
+            }
+            .distinctUntilChanged()
+            .toAnimatedValueFlow(completionEvents = onDozeAnimationComplete)
+
+    override val isVisible: Flow<AnimatedValue<Boolean>> =
+        combine(
+                keyguardTransitionInteractor.finishedKeyguardState.map { it != KeyguardState.GONE },
+                deviceEntryInteractor.isBypassEnabled,
+                areNotifsFullyHiddenAnimated(),
+                isPulseExpandingAnimated(),
+            ) {
+                onKeyguard: Boolean,
+                bypassEnabled: Boolean,
+                (notifsFullyHidden: Boolean, isAnimatingHide: Boolean),
+                (pulseExpanding: Boolean, isAnimatingPulse: Boolean),
+                ->
+                val isAnimating = isAnimatingHide || isAnimatingPulse
+                when {
+                    // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off
+                    // animation is playing, in which case we want them to be visible if we're
+                    // animating in the AOD UI and will be switching to KEYGUARD shortly.
+                    !onKeyguard && !screenOffAnimationController.shouldShowAodIconsWhenShade() ->
+                        AnimatedValue(false, isAnimating = false)
+                    // If we're bypassing, then we're visible
+                    bypassEnabled -> AnimatedValue(true, isAnimating)
+                    // If we are pulsing (and not bypassing), then we are hidden
+                    pulseExpanding -> AnimatedValue(false, isAnimating)
+                    // If notifs are fully gone, then we're visible
+                    notifsFullyHidden -> AnimatedValue(true, isAnimating)
+                    // Otherwise, we're hidden
+                    else -> AnimatedValue(false, isAnimating)
+                }
+            }
+            .distinctUntilChanged()
+
+    override fun completeDozeAnimation() {
+        onDozeAnimationComplete.tryEmit(Unit)
+    }
+
+    override fun completeVisibilityAnimation() {
+        onVisAnimationComplete.tryEmit(Unit)
+    }
+
+    /** Is there an expanded pulse, are we animating in response? */
+    private fun isPulseExpandingAnimated(): Flow<AnimatedValue<Boolean>> {
+        return notificationsKeyguardInteractor.isPulseExpanding
+            .pairwise(initialValue = null)
+            // If pulsing changes, start animating, unless it's the first emission
+            .map { (prev, expanding) ->
+                AnimatableEvent(expanding!!, startAnimating = prev != null)
+            }
+            .toAnimatedValueFlow(completionEvents = onVisAnimationComplete)
+    }
+
+    /** Are notifications completely hidden from view, are we animating in response? */
+    private fun areNotifsFullyHiddenAnimated(): Flow<AnimatedValue<Boolean>> {
+        return notificationsKeyguardInteractor.areNotificationsFullyHidden
+            .pairwise(initialValue = null)
+            .sample(deviceEntryInteractor.isBypassEnabled) { (prev, fullyHidden), bypassEnabled ->
+                val animate =
+                    when {
+                        // Don't animate for the first value
+                        prev == null -> false
+                        // Always animate if bypass is enabled.
+                        bypassEnabled -> true
+                        // If we're not bypassing and we're not going to AOD, then we're not
+                        // animating.
+                        !dozeParameters.alwaysOn -> false
+                        // Don't animate when going to AOD if the display needs blanking.
+                        dozeParameters.displayNeedsBlanking -> false
+                        // We only want the appear animations to happen when the notifications
+                        // get fully hidden, since otherwise the un-hide animation overlaps.
+                        featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> true
+                        else -> fullyHidden!!
+                    }
+                AnimatableEvent(fullyHidden!!, animate)
+            }
+            .toAnimatedValueFlow(completionEvents = onVisAnimationComplete)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
index 933c76f..c44a2b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
@@ -15,8 +15,18 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import com.android.systemui.util.ui.AnimatedValue
 import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flowOf
 
 /** View-model for the overflow row of notification icons displayed in the notification shade. */
 class NotificationIconContainerShelfViewModel @Inject constructor() :
-    NotificationIconContainerViewModel
+    NotificationIconContainerViewModel {
+    override val animationsEnabled: Flow<Boolean> = flowOf(true)
+    override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow()
+    override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow()
+    override fun completeDozeAnimation() {}
+    override fun completeVisibilityAnimation() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
index 2217646..035687a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -15,8 +15,31 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.util.ui.AnimatedValue
 import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.emptyFlow
 
 /** View-model for the row of notification icons displayed in the status bar, */
-class NotificationIconContainerStatusBarViewModel @Inject constructor() :
-    NotificationIconContainerViewModel
+class NotificationIconContainerStatusBarViewModel
+@Inject
+constructor(
+    keyguardInteractor: KeyguardInteractor,
+    shadeInteractor: ShadeInteractor,
+) : NotificationIconContainerViewModel {
+    override val animationsEnabled: Flow<Boolean> =
+        combine(
+            shadeInteractor.isShadeTouchable,
+            keyguardInteractor.isKeyguardShowing,
+        ) { panelTouchesEnabled, isKeyguardShowing ->
+            panelTouchesEnabled && !isKeyguardShowing
+        }
+
+    override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow()
+    override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow()
+    override fun completeDozeAnimation() {}
+    override fun completeVisibilityAnimation() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
index 892b2be..65eb220 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
@@ -15,8 +15,32 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import com.android.systemui.util.ui.AnimatedValue
+import kotlinx.coroutines.flow.Flow
+
 /**
  * View-model for the row of notification icons displayed in the NotificationShelf, StatusBar, and
  * AOD.
  */
-interface NotificationIconContainerViewModel
+interface NotificationIconContainerViewModel {
+    /** Are changes to the icon container animated? */
+    val animationsEnabled: Flow<Boolean>
+
+    /** Should icons be rendered in "dozing" mode? */
+    val isDozing: Flow<AnimatedValue<Boolean>>
+
+    /** Is the icon container visible? */
+    val isVisible: Flow<AnimatedValue<Boolean>>
+
+    /**
+     * Signal completion of the [isDozing] animation; if [isDozing]'s [AnimatedValue.isAnimating]
+     * property was `true`, calling this method will update it to `false.
+     */
+    fun completeDozeAnimation()
+
+    /**
+     * Signal completion of the [isVisible] animation; if [isVisible]'s [AnimatedValue.isAnimating]
+     * property was `true`, calling this method will update it to `false.
+     */
+    fun completeVisibilityAnimation()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt
index 197ae1a..dc9028d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryDumper.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.dump.DumpsysTableLogger
 import com.android.systemui.dump.Row
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import dalvik.annotation.optimization.NeverCompile
 import java.io.PrintWriter
 import javax.inject.Inject
 
@@ -39,6 +40,7 @@
         Log.i("NotificationMemory", "Registered dumpable.")
     }
 
+    @NeverCompile
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         val memoryUse =
             NotificationMemoryMeter.notificationMemoryUse(notificationPipeline.allNotifs)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index c61258b..847d948 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -355,12 +355,8 @@
             AnimatorListenerAdapter animationListener) {
         enableAppearDrawing(true);
         mIsHeadsUpAnimation = isHeadsUpAnimation;
-        if (mDrawingAppearAnimation) {
-            startAppearAnimation(false /* isAppearing */, translationDirection,
-                    delay, duration, onFinishedRunnable, animationListener);
-        } else if (onFinishedRunnable != null) {
-            onFinishedRunnable.run();
-        }
+        startAppearAnimation(false /* isAppearing */, translationDirection,
+                delay, duration, onFinishedRunnable, animationListener);
         return 0;
     }
 
@@ -369,10 +365,8 @@
             Runnable onFinishRunnable) {
         enableAppearDrawing(true);
         mIsHeadsUpAnimation = isHeadsUpAppear;
-        if (mDrawingAppearAnimation) {
-            startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay,
-                    duration, null, null);
-        }
+        startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay,
+                duration, null, null);
     }
 
     private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
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 d18f991..bc570f2 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
@@ -27,7 +27,6 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Notification;
-import android.app.NotificationChannel;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -40,8 +39,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Trace;
-import android.service.notification.StatusBarNotification;
-import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.IndentingPrintWriter;
@@ -73,15 +70,15 @@
 import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.widget.CachingIconView;
 import com.android.internal.widget.CallLayout;
-import com.android.systemui.res.R;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.flags.ViewRefactorFlag;
+import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarIconView;
@@ -274,8 +271,8 @@
     private OnExpandClickListener mOnExpandClickListener;
     private View.OnClickListener mOnFeedbackClickListener;
     private Path mExpandingClipPath;
-    private final ViewRefactorFlag mInlineReplyAnimation =
-            new ViewRefactorFlag(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION);
+    private final RefactorFlag mInlineReplyAnimation =
+            RefactorFlag.forView(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION);
 
     // Listener will be called when receiving a long click event.
     // Use #setLongPressPosition to optionally assign positional data with the long press.
@@ -772,6 +769,7 @@
     /**
      * @return if the view is in heads up state, i.e either still heads upped or it's disappearing.
      */
+    @Override
     public boolean isHeadsUpState() {
         return mIsHeadsUp || mHeadsupDisappearRunning;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
index 2599231..2a3e69b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
@@ -28,9 +28,9 @@
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
-import com.android.systemui.res.R;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.flags.ViewRefactorFlag;
+import com.android.systemui.flags.RefactorFlag;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.RoundableState;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
 import com.android.systemui.util.DumpUtilsKt;
@@ -49,8 +49,8 @@
     private float mOutlineAlpha = -1f;
     private boolean mAlwaysRoundBothCorners;
     private Path mTmpPath = new Path();
-    protected final ViewRefactorFlag mImprovedHunAnimation =
-            new ViewRefactorFlag(Flags.IMPROVED_HUN_ANIMATIONS);
+    protected final RefactorFlag mImprovedHunAnimation =
+            RefactorFlag.forView(Flags.IMPROVED_HUN_ANIMATIONS);
 
     /**
      * {@code false} if the children views of the {@link ExpandableOutlineView} are translated when
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 5aae488..f2f55a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -621,6 +621,10 @@
         return false;
     }
 
+    public boolean isHeadsUpState() {
+        return false;
+    }
+
     public boolean isChildInGroup() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
index 42c80ed..40897da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
@@ -42,9 +42,8 @@
 import android.widget.TextView;
 
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.util.Compile;
@@ -76,7 +75,9 @@
             final StatusBarNotification sbn,
             final NotificationEntry entry,
             final ExpandableNotificationRow row,
-            final AssistantFeedbackController controller) {
+            final AssistantFeedbackController controller,
+            final IStatusBarService statusBarService,
+            final NotificationGutsManager notificationGutsManager) {
         mPkg = sbn.getPackageName();
         mPm = pm;
         mEntry = entry;
@@ -84,8 +85,8 @@
         mRanking = entry.getRanking();
         mFeedbackController = controller;
         mAppName = mPkg;
-        mStatusBarService = Dependency.get(IStatusBarService.class);
-        mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
+        mStatusBarService = statusBarService;
+        mNotificationGutsManager = notificationGutsManager;
 
         bindHeader();
         bindPrompt();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 6d656605..9e9116b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -44,9 +44,9 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.settingslib.notification.ConversationIconFactory;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -54,6 +54,7 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.shade.ShadeController;
@@ -69,8 +70,8 @@
 import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.wmshell.BubblesManager;
 
@@ -99,6 +100,7 @@
     // Dependencies:
     private final NotificationLockscreenUserManager mLockscreenUserManager;
     private final StatusBarStateController mStatusBarStateController;
+    private final IStatusBarService mStatusBarService;
     private final DeviceProvisionedController mDeviceProvisionedController;
     private final AssistantFeedbackController mAssistantFeedbackController;
 
@@ -127,7 +129,7 @@
     private final ShadeController mShadeController;
     private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
     private NotifGutsViewListener mGutsListener;
-    private final HeadsUpManagerPhone mHeadsUpManagerPhone;
+    private final HeadsUpManager mHeadsUpManager;
     private final ActivityStarter mActivityStarter;
 
     @Inject
@@ -152,9 +154,10 @@
             WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             StatusBarStateController statusBarStateController,
+            IStatusBarService statusBarService,
             DeviceProvisionedController deviceProvisionedController,
             MetricsLogger metricsLogger,
-            HeadsUpManagerPhone headsUpManagerPhone,
+            HeadsUpManager headsUpManager,
             ActivityStarter activityStarter) {
         mContext = context;
         mMainHandler = mainHandler;
@@ -177,9 +180,10 @@
         mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
         mLockscreenUserManager = notificationLockscreenUserManager;
         mStatusBarStateController = statusBarStateController;
+        mStatusBarService = statusBarService;
         mDeviceProvisionedController = deviceProvisionedController;
         mMetricsLogger = metricsLogger;
-        mHeadsUpManagerPhone = headsUpManagerPhone;
+        mHeadsUpManager = headsUpManager;
         mActivityStarter = activityStarter;
     }
 
@@ -296,7 +300,7 @@
             if (mGutsListener != null) {
                 mGutsListener.onGutsClose(entry);
             }
-            mHeadsUpManagerPhone.setGutsShown(row.getEntry(), false);
+            mHeadsUpManager.setGutsShown(row.getEntry(), false);
         });
 
         View gutsView = item.getGutsView();
@@ -358,7 +362,8 @@
         PackageManager pmUser = CentralSurfaces.getPackageManagerForUser(mContext,
                 userHandle.getIdentifier());
 
-        feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController);
+        feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController,
+                mStatusBarService, this);
     }
 
     /**
@@ -676,7 +681,7 @@
                 row.closeRemoteInput();
                 mListContainer.onHeightChanged(row, true /* needsAnimation */);
                 mGutsMenuItem = menuItem;
-                mHeadsUpManagerPhone.setGutsShown(row.getEntry(), true);
+                mHeadsUpManager.setGutsShown(row.getEntry(), true);
             }
         };
         guts.post(mOpenRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index 0c686be..e200b90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -167,7 +167,7 @@
     }
 
     @VisibleForTesting
-    boolean isSecondaryVisible() {
+    public boolean isSecondaryVisible() {
         return mIsSecondaryVisible;
     }
 
@@ -179,7 +179,8 @@
         return mIsVisible;
     }
 
-    void setDuration(int duration) {
+    @VisibleForTesting
+    public void setDuration(int duration) {
         mDuration = duration;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 28f0a0c..6f3cd5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -86,12 +86,12 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.ExpandHelper;
-import com.android.systemui.res.R;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.flags.ViewRefactorFlag;
+import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shade.TouchLogger;
 import com.android.systemui.statusbar.CommandQueue;
@@ -106,12 +106,12 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.notification.row.FooterView;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
@@ -200,8 +200,10 @@
     private Set<Integer> mDebugTextUsedYPositions;
     private final boolean mDebugRemoveAnimation;
     private final boolean mSensitiveRevealAnimEndabled;
-    private final ViewRefactorFlag mAnimatedInsets;
-    private final ViewRefactorFlag mShelfRefactor;
+    private final RefactorFlag mAnimatedInsets;
+    private final RefactorFlag mShelfRefactor;
+
+    private final boolean mNewAodTransition;
 
     private int mContentHeight;
     private float mIntrinsicContentHeight;
@@ -485,8 +487,6 @@
     private ShadeController mShadeController;
     private Consumer<Boolean> mOnStackYChanged;
 
-    protected boolean mClearAllEnabled;
-
     private Interpolator mHideXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
 
     private final NotificationSectionsManager mSectionsManager;
@@ -632,11 +632,12 @@
         mIsSmallLandscapeLockscreenEnabled = featureFlags.isEnabled(
                 Flags.LOCKSCREEN_ENABLE_LANDSCAPE);
         mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES);
+        mNewAodTransition = featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION);
         mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
         mSensitiveRevealAnimEndabled = featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM);
         mAnimatedInsets =
-                new ViewRefactorFlag(featureFlags, Flags.ANIMATED_NOTIFICATION_SHADE_INSETS);
-        mShelfRefactor = new ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
+                new RefactorFlag(featureFlags, Flags.ANIMATED_NOTIFICATION_SHADE_INSETS);
+        mShelfRefactor = new RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
         mSectionsManager = Dependency.get(NotificationSectionsManager.class);
         mScreenOffAnimationController =
                 Dependency.get(ScreenOffAnimationController.class);
@@ -670,7 +671,6 @@
             mDebugPaint.setStyle(Paint.Style.STROKE);
             mDebugPaint.setTextSize(25f);
         }
-        mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
         mGroupMembershipManager = Dependency.get(GroupMembershipManager.class);
         mGroupExpansionManager = Dependency.get(GroupExpansionManager.class);
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -758,8 +758,7 @@
     }
 
     private boolean shouldShowDismissView() {
-        return mClearAllEnabled
-                && mController.hasActiveClearableNotifications(ROWS_ALL);
+        return mController.hasActiveClearableNotifications(ROWS_ALL);
     }
 
     private boolean shouldShowFooterView(boolean showDismissView) {
@@ -1432,12 +1431,14 @@
 
     @VisibleForTesting
     public void updateStackHeight(float endHeight, float fraction) {
-        // During the (AOD<=>LS) transition where dozeAmount is changing,
-        // apply dozeAmount to stack height instead of expansionFraction
-        // to unfurl notifications on AOD=>LS wakeup (and furl up on LS=>AOD sleep)
-        final float dozeAmount = mAmbientState.getDozeAmount();
-        if (0f < dozeAmount && dozeAmount < 1f) {
-            fraction = 1f - dozeAmount;
+        if (!mNewAodTransition) {
+            // During the (AOD<=>LS) transition where dozeAmount is changing,
+            // apply dozeAmount to stack height instead of expansionFraction
+            // to unfurl notifications on AOD=>LS wakeup (and furl up on LS=>AOD sleep)
+            final float dozeAmount = mAmbientState.getDozeAmount();
+            if (0f < dozeAmount && dozeAmount < 1f) {
+                fraction = 1f - dozeAmount;
+            }
         }
         mAmbientState.setStackHeight(
                 MathUtils.lerp(endHeight * StackScrollAlgorithm.START_FRACTION,
@@ -5173,7 +5174,6 @@
                     DumpUtilsKt.withIncreasedIndent(
                             pw,
                             () -> {
-                                pw.println("mClearAllEnabled: " + mClearAllEnabled);
                                 pw.println(
                                         "hasActiveClearableNotifications: "
                                                 + mController.hasActiveClearableNotifications(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 66b2555..5020780 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -64,7 +64,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.flags.ViewRefactorFlag;
+import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
 import com.android.systemui.keyguard.shared.model.KeyguardState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -99,7 +99,6 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.NotifStackController;
@@ -115,10 +114,10 @@
 import com.android.systemui.statusbar.notification.row.NotificationGuts;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationSnooze;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor;
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -127,6 +126,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -156,7 +156,7 @@
     private final NotificationGutsManager mNotificationGutsManager;
     private final NotificationsController mNotificationsController;
     private final NotificationVisibilityProvider mVisibilityProvider;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final NotificationRoundnessManager mNotificationRoundnessManager;
     private final TunerService mTunerService;
     private final DeviceProvisionedController mDeviceProvisionedController;
@@ -194,7 +194,7 @@
 
     private final GroupExpansionManager mGroupExpansionManager;
     private final NotifPipelineFlags mNotifPipelineFlags;
-    private final SeenNotificationsProvider mSeenNotificationsProvider;
+    private final NotificationListInteractor mNotificationListInteractor;
     private final KeyguardTransitionRepository mKeyguardTransitionRepo;
 
     private NotificationStackScrollLayout mView;
@@ -207,7 +207,7 @@
     private boolean mIsInTransitionToAod = false;
 
     private final FeatureFlags mFeatureFlags;
-    private final ViewRefactorFlag mShelfRefactor;
+    private final RefactorFlag mShelfRefactor;
     private final NotificationTargetsHelper mNotificationTargetsHelper;
     private final SecureSettings mSecureSettings;
     private final NotificationDismissibilityProvider mDismissibilityProvider;
@@ -631,7 +631,7 @@
             NotificationGutsManager notificationGutsManager,
             NotificationsController notificationsController,
             NotificationVisibilityProvider visibilityProvider,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             NotificationRoundnessManager notificationRoundnessManager,
             TunerService tunerService,
             DeviceProvisionedController deviceProvisionedController,
@@ -662,7 +662,7 @@
             UiEventLogger uiEventLogger,
             NotificationRemoteInputManager remoteInputManager,
             VisibilityLocationProviderDelegator visibilityLocationProviderDelegator,
-            SeenNotificationsProvider seenNotificationsProvider,
+            NotificationListInteractor notificationListInteractor,
             ShadeController shadeController,
             InteractionJankMonitor jankMonitor,
             StackStateLogger stackLogger,
@@ -715,11 +715,11 @@
         mUiEventLogger = uiEventLogger;
         mRemoteInputManager = remoteInputManager;
         mVisibilityLocationProviderDelegator = visibilityLocationProviderDelegator;
-        mSeenNotificationsProvider = seenNotificationsProvider;
+        mNotificationListInteractor = notificationListInteractor;
         mShadeController = shadeController;
         mNotifIconAreaController = notifIconAreaController;
         mFeatureFlags = featureFlags;
-        mShelfRefactor = new ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
+        mShelfRefactor = new RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
         mNotificationTargetsHelper = notificationTargetsHelper;
         mSecureSettings = secureSettings;
         mDismissibilityProvider = dismissibilityProvider;
@@ -2006,7 +2006,7 @@
         public void setNotifStats(@NonNull NotifStats notifStats) {
             mNotifStats = notifStats;
             mView.setHasFilteredOutSeenNotifications(
-                    mSeenNotificationsProvider.getHasFilteredOutSeenNotifications());
+                    mNotificationListInteractor.getHasFilteredOutSeenNotifications().getValue());
             updateFooter();
             updateShowEmptyShadeView();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index f2d5394..80f98a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -27,16 +27,16 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.SystemBarUtils;
 import com.android.keyguard.BouncerPanelExpansionCalculator;
-import com.android.systemui.res.R;
 import com.android.systemui.animation.ShadeInterpolation;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.notification.SourceType;
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.notification.row.FooterView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -142,7 +142,15 @@
                 viewState.setAlpha(1f);
             } else if (ambientState.isOnKeyguard()) {
                 // Adjust alpha for wakeup to lockscreen.
-                viewState.setAlpha(1f - ambientState.getHideAmount());
+                if (view.isHeadsUpState()) {
+                    // Pulsing HUN should be visible on AOD and stay visible during 
+                    // AOD=>lockscreen transition
+                    viewState.setAlpha(1f - ambientState.getHideAmount());
+                } else {
+                    // Normal notifications are hidden on AOD and should fade in during 
+                    // AOD=>lockscreen transition
+                    viewState.setAlpha(1f - ambientState.getDozeAmount());
+                }
             } else if (ambientState.isExpansionChanging()) {
                 // Adjust alpha for shade open & close.
                 float expansion = ambientState.getExpansionFraction();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt
new file mode 100644
index 0000000..f6ed8c8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.stack.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/** Repository for information about the current notification list. */
+@SysUISingleton
+class NotificationListRepository @Inject constructor() {
+    private val _hasFilteredOutSeenNotifications = MutableStateFlow(false)
+    val hasFilteredOutSeenNotifications: StateFlow<Boolean> =
+        _hasFilteredOutSeenNotifications.asStateFlow()
+
+    fun setHasFilteredOutSeenNotifications(value: Boolean) {
+        _hasFilteredOutSeenNotifications.value = value
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt
new file mode 100644
index 0000000..3fd68a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.stack.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+
+/** Interactor for business logic associated with the notification stack. */
+@SysUISingleton
+class NotificationListInteractor
+@Inject
+constructor(
+    private val notificationListRepository: NotificationListRepository,
+) {
+    /** Are any already-seen notifications currently filtered out of the shade? */
+    val hasFilteredOutSeenNotifications: StateFlow<Boolean>
+        get() = notificationListRepository.hasFilteredOutSeenNotifications
+
+    fun setHasFilteredOutSeenNotifications(value: Boolean) {
+        notificationListRepository.setHasFilteredOutSeenNotifications(value)
+    }
+}
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 697d297..3877bb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -28,15 +28,15 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.NightDisplayListenerModule;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.ReduceBrightColorsController;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.DataSaverController;
@@ -461,8 +461,8 @@
     };
 
     @VisibleForTesting
-    protected SettingObserver getSecureSettingForKey(String key) {
-        for (SettingObserver s : mAutoAddSettingList) {
+    protected UserSettingObserver getSecureSettingForKey(String key) {
+        for (UserSettingObserver s : mAutoAddSettingList) {
             if (Objects.equals(key, s.getKey())) {
                 return s;
             }
@@ -476,7 +476,7 @@
      * When the setting changes to a value different from 0, if the tile has not been auto added
      * before, it will be added and the listener will be stopped.
      */
-    private class AutoAddSetting extends SettingObserver {
+    private class AutoAddSetting extends UserSettingObserver {
         private final String mSpec;
 
         AutoAddSetting(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 3e2f10d..ed1c4ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -220,6 +220,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -236,6 +237,10 @@
 import com.android.wm.shell.startingsurface.SplashscreenContentDrawer;
 import com.android.wm.shell.startingsurface.StartingSurface;
 
+import dagger.Lazy;
+
+import dalvik.annotation.optimization.NeverCompile;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.List;
@@ -247,8 +252,6 @@
 import javax.inject.Named;
 import javax.inject.Provider;
 
-import dagger.Lazy;
-
 /**
  * A class handling initialization and coordination between some of the key central surfaces in
  * System UI: The notification shade, the keyguard (lockscreen), and the status bar.
@@ -417,7 +420,7 @@
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
     private final KeyguardBypassController mKeyguardBypassController;
     private final KeyguardStateController mKeyguardStateController;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
     private final FalsingCollector mFalsingCollector;
     private final FalsingManager mFalsingManager;
@@ -611,7 +614,7 @@
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
             KeyguardStateController keyguardStateController,
-            HeadsUpManagerPhone headsUpManagerPhone,
+            HeadsUpManager headsUpManager,
             DynamicPrivacyController dynamicPrivacyController,
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
@@ -718,7 +721,7 @@
         mWakeUpCoordinator = notificationWakeUpCoordinator;
         mKeyguardBypassController = keyguardBypassController;
         mKeyguardStateController = keyguardStateController;
-        mHeadsUpManager = headsUpManagerPhone;
+        mHeadsUpManager = headsUpManager;
         mBackActionInteractor = backActionInteractor;
         mKeyguardIndicationController = keyguardIndicationController;
         mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
@@ -1088,11 +1091,6 @@
     void initShadeVisibilityListener() {
         mShadeController.setVisibilityListener(new ShadeController.ShadeVisibilityListener() {
             @Override
-            public void visibilityChanged(boolean visible) {
-                onShadeVisibilityChanged(visible);
-            }
-
-            @Override
             public void expandedVisibleChanged(boolean expandedVisible) {
                 if (expandedVisible) {
                     setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
@@ -1195,7 +1193,7 @@
                 });
         mStatusBarInitializer.initializeStatusBar();
 
-        mStatusBarTouchableRegionManager.setup(this, getNotificationShadeWindowView());
+        mStatusBarTouchableRegionManager.setup(getNotificationShadeWindowView());
 
         createNavigationBar(result);
 
@@ -1767,6 +1765,7 @@
         }
     }
 
+    @NeverCompile
     @Override
     public void dump(PrintWriter pwOriginal, String[] args) {
         IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
@@ -2603,7 +2602,10 @@
                         mShouldDelayWakeUpAnimation);
 
                 updateIsKeyguard();
+                // TODO(b/301913237): can't delay transition if config_displayBlanksAfterDoze=true,
+                // otherwise, the clock will flicker during LOCKSCREEN_TRANSITION_FROM_AOD
                 mShouldDelayLockscreenTransitionFromAod = mDozeParameters.getAlwaysOn()
+                        && !mDozeParameters.getDisplayNeedsBlanking()
                         && mFeatureFlags.isEnabled(
                                 Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD);
                 if (!mShouldDelayLockscreenTransitionFromAod) {
@@ -2688,7 +2690,9 @@
                 !mDozeServiceHost.isPulsing(), mDeviceProvisionedController.isFrpActive());
 
         mShadeSurface.setTouchAndAnimationDisabled(disabled);
-        mNotificationIconAreaController.setAnimationsEnabled(!disabled);
+        if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            mNotificationIconAreaController.setAnimationsEnabled(!disabled);
+        }
     }
 
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@@ -2844,13 +2848,16 @@
         mScrimController.setExpansionAffectsAlpha(!unlocking);
 
         if (mAlternateBouncerInteractor.isVisibleState()) {
-            if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded())
-                    && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
-                    || mTransitionToFullShadeProgress > 0f)) {
-                mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
-            } else {
-                mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED);
+            if (!mFeatureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+                if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded())
+                        && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
+                        || mTransitionToFullShadeProgress > 0f)) {
+                    mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
+                } else {
+                    mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED);
+                }
             }
+
             // This will cancel the keyguardFadingAway animation if it is running. We need to do
             // this as otherwise it can remain pending and leave keyguard in a weird state.
             mUnlockScrimCallback.onCancelled();
@@ -2913,8 +2920,6 @@
 
     protected boolean mDeviceInteractive;
 
-    protected boolean mVisible;
-
     protected DevicePolicyManager mDevicePolicyManager;
     private final PowerManager mPowerManager;
     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -3032,16 +3037,6 @@
                 afterKeyguardGone);
     }
 
-    private void onShadeVisibilityChanged(boolean visible) {
-        if (mVisible != visible) {
-            mVisible = visible;
-            if (visible) {
-                DejankUtils.notifyRendererOfExpensiveFrame(
-                        getNotificationShadeWindowView(), "onShadeVisibilityChanged");
-            }
-        }
-    }
-
     private void clearNotificationEffects() {
         try {
             mBarService.clearNotificationEffects();
@@ -3163,7 +3158,6 @@
             // TODO: Bring these out of CentralSurfaces.
             mUserInfoControllerImpl.onDensityOrFontScaleChanged();
             mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
-            mHeadsUpManager.onDensityOrFontScaleChanged();
         }
 
         @Override
@@ -3200,7 +3194,8 @@
                     // down on the lockscreen), clear notification LED, vibration,
                     // ringing.
                     // Other transitions are covered in WindowRootViewVisibilityInteractor.
-                    if (mVisible && (newState == StatusBarState.SHADE_LOCKED
+                    if (mWindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible().getValue()
+                            && (newState == StatusBarState.SHADE_LOCKED
                             || mStatusBarStateController.goingToFullShade())) {
                         clearNotificationEffects();
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 4849f64..d3d11ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -49,6 +49,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.Assert;
 
@@ -80,7 +81,7 @@
     private final WakefulnessLifecycle mWakefulnessLifecycle;
     private final SysuiStatusBarStateController mStatusBarStateController;
     private final DeviceProvisionedController mDeviceProvisionedController;
-    private final HeadsUpManagerPhone mHeadsUpManagerPhone;
+    private final HeadsUpManager mHeadsUpManager;
     private final BatteryController mBatteryController;
     private final ScrimController mScrimController;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@@ -106,7 +107,7 @@
             WakefulnessLifecycle wakefulnessLifecycle,
             SysuiStatusBarStateController statusBarStateController,
             DeviceProvisionedController deviceProvisionedController,
-            HeadsUpManagerPhone headsUpManagerPhone, BatteryController batteryController,
+            HeadsUpManager headsUpManager, BatteryController batteryController,
             ScrimController scrimController,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             Lazy<AssistManager> assistManagerLazy,
@@ -123,7 +124,7 @@
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mStatusBarStateController = statusBarStateController;
         mDeviceProvisionedController = deviceProvisionedController;
-        mHeadsUpManagerPhone = headsUpManagerPhone;
+        mHeadsUpManager = headsUpManager;
         mBatteryController = batteryController;
         mScrimController = scrimController;
         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
@@ -135,7 +136,7 @@
         mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
         mAuthController = authController;
         mNotificationIconAreaController = notificationIconAreaController;
-        mHeadsUpManagerPhone.addListener(mOnHeadsUpChangedListener);
+        mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
         mDozeInteractor = dozeInteractor;
     }
 
@@ -337,8 +338,8 @@
         if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) {
             mScrimController.setWakeLockScreenSensorActive(true);
         }
-        if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) {
-            mHeadsUpManagerPhone.extendHeadsUp();
+        if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) {
+            mHeadsUpManager.extendHeadsUp();
         } else {
             mDozeScrimController.extendPulse();
         }
@@ -493,7 +494,7 @@
                     mDozeScrimController.cancelPendingPulseTimeout();
                 }
             }
-            if (!isHeadsUp && !mHeadsUpManagerPhone.hasNotifications()) {
+            if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
                 // There are no longer any notifications to show.  We should end the
                 // pulse now.
                 stopPulsing();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 270c40e..c493eeda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -26,9 +26,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ViewClippingUtil;
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeHeadsUpTracker;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope;
 import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.ViewController;
@@ -70,7 +71,7 @@
     private static final SourceType HEADS_UP = SourceType.from("HeadsUp");
     private static final SourceType PULSING = SourceType.from("Pulsing");
     private final NotificationIconAreaController mNotificationIconAreaController;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final NotificationStackScrollLayoutController mStackScrollerController;
 
     private final DarkIconDispatcher mDarkIconDispatcher;
@@ -108,7 +109,7 @@
     @Inject
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             StatusBarStateController stateController,
             PhoneStatusBarTransitions phoneStatusBarTransitions,
             KeyguardBypassController bypassController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index a5ea142..6b4382f73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -29,11 +29,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.policy.SystemBarUtils;
-import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -42,10 +42,12 @@
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.AnimationStateHandler;
+import com.android.systemui.statusbar.policy.BaseHeadsUpManager;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -53,11 +55,11 @@
 import java.util.List;
 import java.util.Stack;
 
-/**
- * A implementation of HeadsUpManager for phone and car.
- */
-public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
-        OnHeadsUpChangedListener {
+import javax.inject.Inject;
+
+/** A implementation of HeadsUpManager for phone. */
+@SysUISingleton
+public class HeadsUpManagerPhone extends BaseHeadsUpManager implements OnHeadsUpChangedListener {
     private static final String TAG = "HeadsUpManagerPhone";
 
     @VisibleForTesting
@@ -102,7 +104,7 @@
 
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  Constructor:
-
+    @Inject
     public HeadsUpManagerPhone(@NonNull final Context context,
             HeadsUpManagerLogger logger,
             StatusBarStateController statusBarStateController,
@@ -154,7 +156,8 @@
     /**
      * Add a listener to receive callbacks onHeadsUpGoingAway
      */
-    void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) {
+    @Override
+    public void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) {
         mHeadsUpPhoneListeners.add(listener);
     }
 
@@ -162,7 +165,8 @@
      * Gets the touchable region needed for heads up notifications. Returns null if no touchable
      * region is required (ie: no heads up notification currently exists).
      */
-    @Nullable Region getTouchableRegion() {
+    @Override
+    public @Nullable Region getTouchableRegion() {
         NotificationEntry topEntry = getTopEntry();
 
         // This call could be made in an inconsistent state while the pinnedMode hasn't been
@@ -197,8 +201,9 @@
      * @param key the key of the touched notification
      * @return whether the touch is invalid and should be discarded
      */
-    boolean shouldSwallowClick(@NonNull String key) {
-        HeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
+    @Override
+    public boolean shouldSwallowClick(@NonNull String key) {
+        BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
         return entry != null && mClock.currentTimeMillis() < entry.mPostTime;
     }
 
@@ -238,7 +243,8 @@
      * Set that we are exiting the headsUp pinned mode, but some notifications might still be
      * animating out. This is used to keep the touchable regions in a reasonable state.
      */
-    void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+    @Override
+    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
         if (headsUpGoingAway != mHeadsUpGoingAway) {
             mHeadsUpGoingAway = headsUpGoingAway;
             for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) {
@@ -247,7 +253,8 @@
         }
     }
 
-    boolean isHeadsUpGoingAway() {
+    @Override
+    public boolean isHeadsUpGoingAway() {
         return mHeadsUpGoingAway;
     }
 
@@ -260,8 +267,8 @@
     public void setRemoteInputActive(
             @NonNull NotificationEntry entry, boolean remoteInputActive) {
         HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.getKey());
-        if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
-            headsUpEntry.remoteInputActive = remoteInputActive;
+        if (headsUpEntry != null && headsUpEntry.mRemoteInputActive != remoteInputActive) {
+            headsUpEntry.mRemoteInputActive = remoteInputActive;
             if (remoteInputActive) {
                 headsUpEntry.removeAutoRemovalCallbacks("setRemoteInputActive(true)");
             } else {
@@ -313,6 +320,7 @@
         mSwipedOutKeys.add(key);
     }
 
+    @Override
     public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
             boolean animate) {
         if (animate) {
@@ -411,7 +419,7 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  HeadsUpEntryPhone:
 
-    protected class HeadsUpEntryPhone extends HeadsUpManager.HeadsUpEntry {
+    protected class HeadsUpEntryPhone extends BaseHeadsUpManager.HeadsUpEntry {
 
         private boolean mGutsShownPinned;
 
@@ -459,11 +467,11 @@
 
         @Override
         public void setExpanded(boolean expanded) {
-            if (this.expanded == expanded) {
+            if (this.mExpanded == expanded) {
                 return;
             }
 
-            this.expanded = expanded;
+            this.mExpanded = expanded;
             if (expanded) {
                 removeAutoRemovalCallbacks("setExpanded(true)");
             } else {
@@ -504,21 +512,6 @@
         }
     }
 
-    public interface AnimationStateHandler {
-        void setHeadsUpGoingAwayAnimationsAllowed(boolean allowed);
-    }
-
-    /**
-     * Listener to register for HeadsUpNotification Phone changes.
-     */
-    public interface OnHeadsUpPhoneListenerChange {
-        /**
-         * Called when a heads up notification is 'going away' or no longer 'going away'.
-         * See {@link HeadsUpManagerPhone#setHeadsUpGoingAway}.
-         */
-        void onHeadsUpGoingAwayStateChanged(boolean headsUpGoingAway);
-    }
-
     private final StateListener mStatusBarStateListener = new StateListener() {
         @Override
         public void onStateChanged(int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
new file mode 100644
index 0000000..0d0f2cd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
@@ -0,0 +1,11 @@
+package com.android.systemui.statusbar.phone
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface HeadsUpModule {
+    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: HeadsUpManagerPhone): HeadsUpManager
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index dcbaac2..198272e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -26,13 +26,14 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 /**
  * A helper class to handle touches on the heads-up views.
  */
 public class HeadsUpTouchHelper implements Gefingerpoken {
 
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final IStatusBarService mStatusBarService;
     private final Callback mCallback;
     private int mTrackingPointer;
@@ -45,7 +46,7 @@
     private final HeadsUpNotificationViewController mPanel;
     private ExpandableNotificationRow mPickedChild;
 
-    public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager,
+    public HeadsUpTouchHelper(HeadsUpManager headsUpManager,
             IStatusBarService statusBarService,
             Callback callback,
             HeadsUpNotificationViewController notificationPanelView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 7efa705..58126ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -43,9 +43,9 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
 import com.android.systemui.user.ui.binder.StatusBarUserChipViewBinder;
@@ -367,15 +367,22 @@
         mMultiUserAvatar.setImageDrawable(picture);
     }
 
-    /** Should only be called from {@link KeyguardStatusBarViewController}. */
-    void onBatteryLevelChanged(boolean charging) {
+    /**
+     * Should only be called from {@link KeyguardStatusBarViewController} or
+     * {@link com.android.systemui.statusbar.ui.binder.KeyguardStatusBarViewBinder}.
+     */
+    public void onBatteryChargingChanged(boolean charging) {
         if (mBatteryCharging != charging) {
             mBatteryCharging = charging;
             updateVisibilities();
         }
     }
 
-    void setKeyguardUserSwitcherEnabled(boolean enabled) {
+    /**
+     * Should only be called from {@link KeyguardStatusBarViewController} or
+     * {@link com.android.systemui.statusbar.ui.binder.KeyguardStatusBarViewBinder}.
+     */
+    public void setKeyguardUserSwitcherEnabled(boolean enabled) {
         mKeyguardUserSwitcherEnabled = enabled;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 9cf9714..2960520 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -172,7 +172,7 @@
             new BatteryController.BatteryStateChangeCallback() {
                 @Override
                 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-                    mView.onBatteryLevelChanged(charging);
+                    mView.onBatteryChargingChanged(charging);
                 }
             };
 
@@ -430,11 +430,18 @@
 
     /** Sets whether user switcher is enabled. */
     public void setKeyguardUserSwitcherEnabled(boolean enabled) {
+        if (isMigrationEnabled()) {
+            return;
+        }
         mView.setKeyguardUserSwitcherEnabled(enabled);
     }
 
     /** Sets whether this controller should listen to battery updates. */
     public void setBatteryListening(boolean listening) {
+        if (isMigrationEnabled()) {
+            return;
+        }
+
         if (listening == mBatteryListening) {
             return;
         }
@@ -472,6 +479,10 @@
 
     /** Animate the keyguard status bar in. */
     public void animateKeyguardStatusBarIn() {
+        if (isMigrationEnabled()) {
+            return;
+        }
+
         mLogger.log(TAG, LogLevel.DEBUG, "animating status bar in");
         if (mDisableStateTracker.isDisabled()) {
             // If our view is disabled, don't allow us to animate in.
@@ -488,6 +499,10 @@
 
     /** Animate the keyguard status bar out. */
     public void animateKeyguardStatusBarOut(long startDelay, long duration) {
+        if (isMigrationEnabled()) {
+            return;
+        }
+
         mLogger.log(TAG, LogLevel.DEBUG, "animating status bar out");
         ValueAnimator anim = ValueAnimator.ofFloat(mView.getAlpha(), 0f);
         anim.addUpdateListener(mAnimatorUpdateListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
index 660aa3f..5553270 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
@@ -15,6 +15,8 @@
  */
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.flags.Flags.NEW_AOD_TRANSITION;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Color;
@@ -34,16 +36,16 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.flags.ViewRefactorFlag;
+import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -107,7 +109,9 @@
     private final ArrayList<Rect> mTintAreas = new ArrayList<>();
     private final Context mContext;
 
-    private final ViewRefactorFlag mShelfRefactor;
+    private final RefactorFlag mShelfRefactor;
+
+    private final boolean mNewAodTransition;
 
     private int mAodIconAppearTranslation;
 
@@ -146,7 +150,8 @@
         mContrastColorUtil = ContrastColorUtil.getInstance(context);
         mContext = context;
         mStatusBarStateController = statusBarStateController;
-        mShelfRefactor = new ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
+        mShelfRefactor = new RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
+        mNewAodTransition = featureFlags.isEnabled(NEW_AOD_TRANSITION);
         mStatusBarStateController.addCallback(this);
         mMediaManager = notificationMediaManager;
         mDozeParameters = dozeParameters;
@@ -609,9 +614,11 @@
         boolean animate = true;
         if (!mBypassController.getBypassEnabled()) {
             animate = mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking();
-            // We only want the appear animations to happen when the notifications get fully hidden,
-            // since otherwise the unhide animation overlaps
-            animate &= fullyHidden;
+            if (!mNewAodTransition) {
+                // We only want the appear animations to happen when the notifications get fully
+                // hidden, since otherwise the unhide animation overlaps
+                animate &= fullyHidden;
+            }
         }
         updateAodIconsVisibility(animate, false /* force */);
         updateAodNotificationIcons();
@@ -647,23 +654,34 @@
             mAodIconsVisible = visible;
             mAodIcons.animate().cancel();
             if (animate) {
-                boolean wasFullyInvisible = mAodIcons.getVisibility() != View.VISIBLE;
-                if (mAodIconsVisible) {
-                    if (wasFullyInvisible) {
-                        // No fading here, let's just appear the icons instead!
-                        mAodIcons.setVisibility(View.VISIBLE);
-                        mAodIcons.setAlpha(1.0f);
-                        appearAodIcons();
+                if (mNewAodTransition) {
+                    // Let's make sure the icon are translated to 0, since we cancelled it above
+                    animateInAodIconTranslation();
+                    if (mAodIconsVisible) {
+                        CrossFadeHelper.fadeIn(mAodIcons);
+                    } else {
+                        CrossFadeHelper.fadeOut(mAodIcons);
+                    }
+                } else {
+                    boolean wasFullyInvisible = mAodIcons.getVisibility() != View.VISIBLE;
+                    if (mAodIconsVisible) {
+                        if (wasFullyInvisible) {
+                            // No fading here, let's just appear the icons instead!
+                            mAodIcons.setVisibility(View.VISIBLE);
+                            mAodIcons.setAlpha(1.0f);
+                            appearAodIcons();
+                        } else {
+                            // Let's make sure the icon are translated to 0, since we cancelled it
+                            // above
+                            animateInAodIconTranslation();
+                            // We were fading out, let's fade in instead
+                            CrossFadeHelper.fadeIn(mAodIcons);
+                        }
                     } else {
                         // Let's make sure the icon are translated to 0, since we cancelled it above
                         animateInAodIconTranslation();
-                        // We were fading out, let's fade in instead
-                        CrossFadeHelper.fadeIn(mAodIcons);
+                        CrossFadeHelper.fadeOut(mAodIcons);
                     }
-                } else {
-                    // Let's make sure the icon are translated to 0, since we cancelled it above
-                    animateInAodIconTranslation();
-                    CrossFadeHelper.fadeOut(mAodIcons);
                 }
             } else {
                 mAodIcons.setAlpha(1.0f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 7cbaf63..b15c0fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -33,6 +33,7 @@
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.collection.ArrayMap;
 
@@ -624,12 +625,32 @@
     }
 
     public void setDozing(boolean dozing, boolean fade, long delay) {
+        setDozing(dozing, fade, delay, /* endRunnable= */ null);
+    }
+
+    public void setDozing(boolean dozing, boolean fade, long delay,
+            @Nullable Runnable endRunnable) {
         mDozing = dozing;
         mDisallowNextAnimation |= !fade;
-        for (int i = 0; i < getChildCount(); i++) {
+        final int childCount = getChildCount();
+        // Track all the child invocations of setDozing, invoking the top-level endRunnable once
+        // they have all completed.
+        final Runnable onChildCompleted = endRunnable == null ? null : new Runnable() {
+            private int mPendingCallbacks = childCount;
+
+            @Override
+            public void run() {
+                if (--mPendingCallbacks == 0) {
+                    endRunnable.run();
+                }
+            }
+        };
+        for (int i = 0; i < childCount; i++) {
             View view = getChildAt(i);
             if (view instanceof StatusBarIconView) {
-                ((StatusBarIconView) view).setDozing(dozing, fade, delay);
+                ((StatusBarIconView) view).setDozing(dozing, fade, delay, onChildCompleted);
+            } else if (onChildCompleted != null) {
+                onChildCompleted.run();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index 4b39854..235ed25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -24,6 +24,7 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
 
@@ -39,7 +40,7 @@
     private final ShadeViewController mShadeViewController;
     private final NotificationStackScrollLayoutController mNsslController;
     private final KeyguardBypassController mKeyguardBypassController;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final StatusBarStateController mStatusBarStateController;
     private final NotificationRemoteInputManager mNotificationRemoteInputManager;
 
@@ -50,7 +51,7 @@
             ShadeViewController shadeViewController,
             NotificationStackScrollLayoutController nsslController,
             KeyguardBypassController keyguardBypassController,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             StatusBarStateController statusBarStateController,
             NotificationRemoteInputManager notificationRemoteInputManager) {
         mNotificationShadeWindowController = notificationShadeWindowController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index eedf35f..3adf338 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -296,7 +296,6 @@
 
     final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
     private boolean mIsBackAnimationEnabled;
-    private final boolean mUdfpsNewTouchDetectionEnabled;
     private final UdfpsOverlayInteractor mUdfpsOverlayInteractor;
     private final ActivityStarter mActivityStarter;
 
@@ -398,7 +397,6 @@
         mAlternateBouncerInteractor = alternateBouncerInteractor;
         mIsBackAnimationEnabled =
                 featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM);
-        mUdfpsNewTouchDetectionEnabled = featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION);
         mUdfpsOverlayInteractor = udfpsOverlayInteractor;
         mActivityStarter = activityStarter;
         mKeyguardTransitionInteractor = keyguardTransitionInteractor;
@@ -1573,6 +1571,9 @@
      * notification shade's child views.
      */
     public boolean shouldInterceptTouchEvent(MotionEvent event) {
+        if (mFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+            return false;
+        }
         return mAlternateBouncerInteractor.isVisibleState();
     }
 
@@ -1581,13 +1582,17 @@
      * showing.
      */
     public boolean onTouch(MotionEvent event) {
+        if (mFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) {
+            return false;
+        }
+
         boolean handleTouch = shouldInterceptTouchEvent(event);
         if (handleTouch) {
             final boolean actionDown = event.getActionMasked() == MotionEvent.ACTION_DOWN;
             final boolean actionDownThenUp = mAlternateBouncerInteractor.getReceivedDownTouch()
                     && event.getActionMasked() == MotionEvent.ACTION_UP;
             final boolean udfpsOverlayWillForwardEventsOutsideNotificationShade =
-                    mUdfpsNewTouchDetectionEnabled && mKeyguardUpdateManager.isUdfpsEnrolled();
+                    mKeyguardUpdateManager.isUdfpsEnrolled();
             final boolean actionOutsideShouldDismissAlternateBouncer =
                     event.getActionMasked() == MotionEvent.ACTION_OUTSIDE
                     && !udfpsOverlayWillForwardEventsOutsideNotificationShade;
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 053c27c..dbee080 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -76,6 +76,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController;
 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.wmshell.BubblesManager;
@@ -102,7 +103,7 @@
     private final Executor mUiBgExecutor;
 
     private final NotificationVisibilityProvider mVisibilityProvider;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final ActivityStarter mActivityStarter;
     private final NotificationClickNotifier mClickNotifier;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -141,7 +142,7 @@
             Handler mainThreadHandler,
             Executor uiBgExecutor,
             NotificationVisibilityProvider visibilityProvider,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             ActivityStarter activityStarter,
             NotificationClickNotifier clickNotifier,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@@ -213,12 +214,15 @@
      */
     @Override
     public void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row) {
-        mLogger.logStartingActivityFromClick(entry);
+        mLogger.logStartingActivityFromClick(entry, row.isHeadsUpState(),
+                mKeyguardStateController.isVisible(),
+                mNotificationShadeWindowController.getPanelExpanded());
 
         if (mRemoteInputManager.isRemoteInputActive(entry)) {
             // We have an active remote input typed and the user clicked on the notification.
             // this was probably unintentional, so we're closing the edit text instead.
             mRemoteInputManager.closeRemoteInputs();
+            mLogger.logCloseRemoteInput(entry);
             return;
         }
         Notification notification = entry.getSbn().getNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
index d07378e..4211cab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
@@ -30,11 +30,16 @@
 class StatusBarNotificationActivityStarterLogger @Inject constructor(
     @NotifInteractionLog private val buffer: LogBuffer
 ) {
-    fun logStartingActivityFromClick(entry: NotificationEntry) {
+    fun logStartingActivityFromClick(entry: NotificationEntry, isHeadsUpState: Boolean,
+                                     isKeyguardVisible: Boolean, isPanelExpanded: Boolean) {
         buffer.log(TAG, DEBUG, {
             str1 = entry.logKey
+            bool1 = isHeadsUpState
+            bool2 = isKeyguardVisible
+            bool3 = isPanelExpanded
         }, {
-            "(1/5) onNotificationClicked: $str1"
+            "(1/5) onNotificationClicked: $str1 isHeadsUpState: $bool1 " +
+                    "isKeyguardVisible: $bool2 isPanelExpanded: $bool3"
         })
     }
 
@@ -72,6 +77,14 @@
         })
     }
 
+    fun logCloseRemoteInput(entry: NotificationEntry) {
+        buffer.log(TAG, DEBUG, {
+            str1 = entry.logKey
+        }, {
+            "Closing remote input for $str1"
+        })
+    }
+
     fun logExpandingBubble(entry: NotificationEntry) {
         buffer.log(TAG, DEBUG, {
             str1 = entry.logKey
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index fb7f9d1..2d14f6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -31,11 +31,11 @@
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.InitController;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.NotificationShadeWindowView;
 import com.android.systemui.shade.QuickSettingsController;
 import com.android.systemui.shade.ShadeViewController;
@@ -60,6 +60,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import javax.inject.Inject;
@@ -76,7 +77,7 @@
     private final NotificationMediaManager mMediaManager;
     private final NotificationGutsManager mGutsManager;
     private final ShadeViewController mNotificationPanel;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final AboveShelfObserver mAboveShelfObserver;
     private final DozeScrimController mDozeScrimController;
     private final NotificationsInteractor mNotificationsInteractor;
@@ -98,7 +99,7 @@
             Context context,
             ShadeViewController panel,
             QuickSettingsController quickSettingsController,
-            HeadsUpManagerPhone headsUp,
+            HeadsUpManager headsUp,
             NotificationShadeWindowView statusBarWindow,
             ActivityStarter activityStarter,
             NotificationStackScrollLayoutController stackScrollerController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 40bd8d3..ba73c10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -31,15 +31,18 @@
 
 import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
 import com.android.systemui.ScreenDecorations;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
@@ -58,13 +61,12 @@
     private static final String TAG = "TouchableRegionManager";
 
     private final Context mContext;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
 
     private boolean mIsStatusBarExpanded = false;
     private boolean mShouldAdjustInsets = false;
-    private CentralSurfaces mCentralSurfaces;
     private View mNotificationShadeWindowView;
     private View mNotificationPanelView;
     private boolean mForceCollapsedUntilLayout = false;
@@ -72,6 +74,8 @@
     private Region mTouchableRegion = new Region();
     private int mDisplayCutoutTouchableRegionSize;
     private int mStatusBarHeight;
+    private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+    private final AlternateBouncerInteractor mAlternateBouncerInteractor;
 
     private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener;
 
@@ -80,12 +84,14 @@
             Context context,
             NotificationShadeWindowController notificationShadeWindowController,
             ConfigurationController configurationController,
-            HeadsUpManagerPhone headsUpManager,
+            HeadsUpManager headsUpManager,
             ShadeExpansionStateManager shadeExpansionStateManager,
             Provider<SceneInteractor> sceneInteractor,
             Provider<JavaAdapter> javaAdapter,
             SceneContainerFlags sceneContainerFlags,
-            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController
+            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+            PrimaryBouncerInteractor primaryBouncerInteractor,
+            AlternateBouncerInteractor alternateBouncerInteractor
     ) {
         mContext = context;
         initResources();
@@ -128,13 +134,12 @@
                     this::onShadeExpansionFullyChanged);
         }
 
+        mPrimaryBouncerInteractor = primaryBouncerInteractor;
+        mAlternateBouncerInteractor = alternateBouncerInteractor;
         mOnComputeInternalInsetsListener = this::onComputeInternalInsets;
     }
 
-    protected void setup(
-            @NonNull CentralSurfaces centralSurfaces,
-            @NonNull View notificationShadeWindowView) {
-        mCentralSurfaces = centralSurfaces;
+    protected void setup(@NonNull View notificationShadeWindowView) {
         mNotificationShadeWindowView = notificationShadeWindowView;
         mNotificationPanelView = mNotificationShadeWindowView.findViewById(R.id.notification_panel);
     }
@@ -260,7 +265,8 @@
         // since we don't want stray touches to go through the light reveal scrim to whatever is
         // underneath.
         return mIsStatusBarExpanded
-                || mCentralSurfaces.isBouncerShowing()
+                || mPrimaryBouncerInteractor.isShowing().getValue()
+                || mAlternateBouncerInteractor.isVisibleState()
                 || mUnlockedScreenOffAnimationController.isAnimationPlaying();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index babd435..63c022c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -38,11 +38,11 @@
 import com.android.app.animation.InterpolatorsAndroidX;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -74,8 +74,6 @@
 import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener;
 import com.android.systemui.util.settings.SecureSettings;
 
-import kotlin.Unit;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -85,6 +83,7 @@
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
+import kotlin.Unit;
 
 /**
  * Contains the collapsed status bar and handles hiding/showing based on disable flags
@@ -279,7 +278,8 @@
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         mDumpManager.registerDumpable(getClass().getSimpleName(), this);
-        mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create(this);
+        mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create(
+                (PhoneStatusBarView) getView());
         mStatusBarFragmentComponent.init();
         mStartableStates.clear();
         for (Startable startable : mStatusBarFragmentComponent.getStartables()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
index d9a5844..0618abb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
@@ -27,11 +27,11 @@
 import com.android.systemui.statusbar.phone.StatusBarDemoMode;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 
-import java.util.Set;
-
 import dagger.BindsInstance;
 import dagger.Subcomponent;
 
+import java.util.Set;
+
 /**
  * A subcomponent that gets re-created each time we create a new {@link CollapsedStatusBarFragment}.
  *
@@ -54,7 +54,7 @@
     @Subcomponent.Factory
     interface Factory {
         StatusBarFragmentComponent create(
-                @BindsInstance CollapsedStatusBarFragment collapsedStatusBarFragment);
+                @BindsInstance @RootView PhoneStatusBarView phoneStatusBarView);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index 6ef877b..3741f14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -19,15 +19,14 @@
 import android.view.View;
 import android.view.ViewStub;
 
-import com.android.systemui.res.R;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.dagger.qualifiers.RootView;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
 import com.android.systemui.statusbar.phone.StatusBarLocation;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
@@ -51,15 +50,6 @@
 
     /** */
     @Provides
-    @RootView
-    @StatusBarFragmentScope
-    static PhoneStatusBarView providePhoneStatusBarView(
-            CollapsedStatusBarFragment collapsedStatusBarFragment) {
-        return (PhoneStatusBarView) collapsedStatusBarFragment.getView();
-    }
-
-    /** */
-    @Provides
     @StatusBarFragmentScope
     static BatteryMeterView provideBatteryMeterView(@RootView PhoneStatusBarView view) {
         return view.findViewById(R.id.battery);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
index 8ff9198..8862c77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.pipeline.airplane.data.repository
 
 import android.os.Handler
-import android.os.UserHandle
 import android.provider.Settings.Global
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
@@ -66,13 +65,7 @@
     override val isAirplaneMode: StateFlow<Boolean> =
         conflatedCallbackFlow {
                 val observer =
-                    object :
-                        SettingObserver(
-                            globalSettings,
-                            bgHandler,
-                            Global.AIRPLANE_MODE_ON,
-                            UserHandle.USER_ALL
-                        ) {
+                    object : SettingObserver(globalSettings, bgHandler, Global.AIRPLANE_MODE_ON) {
                         override fun handleValueChanged(value: Int, observedChange: Boolean) {
                             trySend(value == 1)
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
index 9b404f1..e9e52a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
@@ -165,7 +165,7 @@
                     }
 
                 wifiPickerTracker =
-                    wifiPickerTrackerFactory.create(lifecycle, callback).apply {
+                    wifiPickerTrackerFactory.create(lifecycle, callback, "WifiRepository").apply {
                         // By default, [WifiPickerTracker] will scan to see all available wifi
                         // networks in the area. Because SysUI only needs to display the
                         // **connected** network, we don't need scans to be running (and in fact,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index e59ec04..cec76f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -34,8 +34,8 @@
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.EventLogTags;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -47,7 +47,8 @@
  * A manager which handles heads up notifications which is a special mode where
  * they simply peek from the top of the screen.
  */
-public abstract class HeadsUpManager extends AlertingNotificationManager {
+public abstract class BaseHeadsUpManager extends AlertingNotificationManager implements
+        HeadsUpManager {
     private static final String TAG = "HeadsUpManager";
     private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
 
@@ -81,7 +82,7 @@
         }
     }
 
-    public HeadsUpManager(@NonNull final Context context,
+    public BaseHeadsUpManager(@NonNull final Context context,
             HeadsUpManagerLogger logger,
             @Main Handler handler,
             AccessibilityManagerWrapper accessibilityManagerWrapper,
@@ -131,6 +132,7 @@
         mListeners.remove(listener);
     }
 
+    /** Updates the notification with the given key. */
     public void updateNotification(@NonNull String key, boolean alert) {
         super.updateNotification(key, alert);
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
@@ -146,7 +148,7 @@
             // the NotificationEntry into AlertingNotificationManager's mAlertEntries map.
             return hasFullScreenIntent(entry);
         }
-        return hasFullScreenIntent(entry) && !headsUpEntry.wasUnpinned;
+        return hasFullScreenIntent(entry) && !headsUpEntry.mWasUnpinned;
     }
 
     protected boolean hasFullScreenIntent(@NonNull NotificationEntry entry) {
@@ -154,11 +156,11 @@
     }
 
     protected void setEntryPinned(
-            @NonNull HeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) {
+            @NonNull BaseHeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) {
         mLogger.logSetEntryPinned(headsUpEntry.mEntry, isPinned);
         NotificationEntry entry = headsUpEntry.mEntry;
         if (!isPinned) {
-            headsUpEntry.wasUnpinned = true;
+            headsUpEntry.mWasUnpinned = true;
         }
         if (entry.isRowPinned() != isPinned) {
             entry.setRowPinned(isPinned);
@@ -292,10 +294,12 @@
         mUser = user;
     }
 
+    /** Returns the ID of the current user. */
     public int getUser() {
         return  mUser;
     }
 
+    @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("HeadsUpManager state:");
         dumpInternal(pw, args);
@@ -309,9 +313,9 @@
         for (AlertEntry entry: mAlertEntries.values()) {
             pw.print("  HeadsUpEntry="); pw.println(entry.mEntry);
         }
-        int N = mSnoozedPackages.size();
-        pw.println("  snoozed packages: " + N);
-        for (int i = 0; i < N; i++) {
+        int n = mSnoozedPackages.size();
+        pw.println("  snoozed packages: " + n);
+        for (int i = 0; i < n; i++) {
             pw.print("    "); pw.print(mSnoozedPackages.valueAt(i));
             pw.print(", "); pw.println(mSnoozedPackages.keyAt(i));
         }
@@ -399,20 +403,20 @@
      *
      * @param entry the entry that might be indirectly removed by the user's action
      *
-     * @see com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator#mActionPressListener
+     * @see HeadsUpCoordinator#mActionPressListener
      * @see #canRemoveImmediately(String)
      */
     public void setUserActionMayIndirectlyRemove(@NonNull NotificationEntry entry) {
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
         if (headsUpEntry != null) {
-            headsUpEntry.userActionMayIndirectlyRemove = true;
+            headsUpEntry.mUserActionMayIndirectlyRemove = true;
         }
     }
 
     @Override
     public boolean canRemoveImmediately(@NonNull String key) {
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
-        if (headsUpEntry != null && headsUpEntry.userActionMayIndirectlyRemove) {
+        if (headsUpEntry != null && headsUpEntry.mUserActionMayIndirectlyRemove) {
             return true;
         }
         return super.canRemoveImmediately(key);
@@ -424,9 +428,6 @@
         return new HeadsUpEntry();
     }
 
-    public void onDensityOrFontScaleChanged() {
-    }
-
     /**
      * Determines if the notification is for a critical call that must display on top of an active
      * input notification.
@@ -445,16 +446,16 @@
      * lifecycle automatically when created.
      */
     protected class HeadsUpEntry extends AlertEntry {
-        public boolean remoteInputActive;
-        public boolean userActionMayIndirectlyRemove;
+        public boolean mRemoteInputActive;
+        public boolean mUserActionMayIndirectlyRemove;
 
-        protected boolean expanded;
-        protected boolean wasUnpinned;
+        protected boolean mExpanded;
+        protected boolean mWasUnpinned;
 
         @Override
         public boolean isSticky() {
-            return (mEntry.isRowPinned() && expanded)
-                    || remoteInputActive
+            return (mEntry.isRowPinned() && mExpanded)
+                    || mRemoteInputActive
                     || hasFullScreenIntent(mEntry);
         }
 
@@ -490,9 +491,9 @@
                 return 1;
             }
 
-            if (remoteInputActive && !headsUpEntry.remoteInputActive) {
+            if (mRemoteInputActive && !headsUpEntry.mRemoteInputActive) {
                 return -1;
-            } else if (!remoteInputActive && headsUpEntry.remoteInputActive) {
+            } else if (!mRemoteInputActive && headsUpEntry.mRemoteInputActive) {
                 return 1;
             }
 
@@ -500,14 +501,14 @@
         }
 
         public void setExpanded(boolean expanded) {
-            this.expanded = expanded;
+            this.mExpanded = expanded;
         }
 
         @Override
         public void reset() {
             super.reset();
-            expanded = false;
-            remoteInputActive = false;
+            mExpanded = false;
+            mRemoteInputActive = false;
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt
new file mode 100644
index 0000000..21acfb4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * A [Flow] that emits whenever screen density or font scale has changed.
+ *
+ * @see ConfigurationController.ConfigurationListener.onDensityOrFontScaleChanged
+ */
+val ConfigurationController.onDensityOrFontScaleChanged: Flow<Unit>
+    get() =
+        ConflatedCallbackFlow.conflatedCallbackFlow {
+            val listener =
+                object : ConfigurationController.ConfigurationListener {
+                    override fun onDensityOrFontScaleChanged() {
+                        trySend(Unit)
+                    }
+                }
+            addCallback(listener)
+            awaitClose { removeCallback(listener) }
+        }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
index 8c61ada..8b20283 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
@@ -62,7 +62,7 @@
     }
 
     private val deviceProvisionedUri = globalSettings.getUriFor(Settings.Global.DEVICE_PROVISIONED)
-    private val frpActiveUri = secureSettings.getUriFor(Settings.Secure.SECURE_FRP_MODE)
+    private val frpActiveUri = globalSettings.getUriFor(Settings.Global.SECURE_FRP_MODE)
     private val userSetupUri = secureSettings.getUriFor(Settings.Secure.USER_SETUP_COMPLETE)
 
     private val deviceProvisioned = AtomicBoolean(false)
@@ -148,7 +148,7 @@
                     .set(globalSettings.getInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0)
         }
         if (updateFrp) {
-            frpActive.set(globalSettings.getInt(Settings.Secure.SECURE_FRP_MODE, 0) != 0)
+            frpActive.set(globalSettings.getInt(Settings.Global.SECURE_FRP_MODE, 0) != 0)
         }
         synchronized(lock) {
             if (updateUser == ALL_USERS) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
new file mode 100644
index 0000000..d9527fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
@@ -0,0 +1,245 @@
+package com.android.systemui.statusbar.policy
+
+import android.graphics.Region
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import dagger.Binds
+import dagger.Module
+import java.io.PrintWriter
+import java.util.stream.Stream
+import javax.inject.Inject
+
+/**
+ * A manager which handles heads up notifications which is a special mode where they simply peek
+ * from the top of the screen.
+ */
+interface HeadsUpManager : Dumpable {
+    /** The stream of all current notifications managed by this manager. */
+    val allEntries: Stream<NotificationEntry>
+
+    /** Add a listener to receive callbacks onHeadsUpGoingAway. */
+    fun addHeadsUpPhoneListener(listener: OnHeadsUpPhoneListenerChange)
+
+    /** Adds an OnHeadUpChangedListener to observe events. */
+    fun addListener(listener: OnHeadsUpChangedListener)
+
+    fun addSwipedOutNotification(key: String)
+
+    /**
+     * Whether or not the alert can be removed currently. If it hasn't been on screen long enough it
+     * should not be removed unless forced
+     *
+     * @param key the key to check if removable
+     * @return true if the alert entry can be removed
+     */
+    fun canRemoveImmediately(key: String): Boolean
+
+    /**
+     * Compare two entries and decide how they should be ranked.
+     *
+     * @return -1 if the first argument should be ranked higher than the second, 1 if the second one
+     *   should be ranked higher and 0 if they are equal.
+     */
+    fun compare(a: NotificationEntry?, b: NotificationEntry?): Int
+    /**
+     * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
+     * longer.
+     */
+    fun extendHeadsUp()
+
+    /** Returns when a HUN entry should be removed in milliseconds from now. */
+    fun getEarliestRemovalTime(key: String?): Long
+
+    /** Returns the top Heads Up Notification, which appears to show at first. */
+    fun getTopEntry(): NotificationEntry?
+
+    /**
+     * Gets the touchable region needed for heads up notifications. Returns null if no touchable
+     * region is required (ie: no heads up notification currently exists).
+     */
+    fun getTouchableRegion(): Region?
+
+    /**
+     * Whether or not there are any active alerting notifications.
+     *
+     * @return true if there is an alert, false otherwise
+     */
+    fun hasNotifications(): Boolean = false
+
+    /** Returns whether there are any pinned Heads Up Notifications or not. */
+    fun hasPinnedHeadsUp(): Boolean
+
+    /** Returns whether or not the given notification is alerting and managed by this manager. */
+    fun isAlerting(key: String): Boolean
+
+    fun isHeadsUpGoingAway(): Boolean
+
+    /** Returns if the given notification is snoozed or not. */
+    fun isSnoozed(packageName: String): Boolean
+
+    /** Returns whether the entry is (pinned and expanded) or (has an active remote input). */
+    fun isSticky(key: String?): Boolean
+
+    fun isTrackingHeadsUp(): Boolean
+
+    fun onExpandingFinished()
+
+    /** Removes the OnHeadUpChangedListener from the observer list. */
+    fun removeListener(listener: OnHeadsUpChangedListener)
+
+    /**
+     * Try to remove the notification. May not succeed if the notification has not been shown long
+     * enough and needs to be kept around.
+     *
+     * @param key the key of the notification to remove
+     * @param releaseImmediately force a remove regardless of earliest removal time
+     * @return true if notification is removed, false otherwise
+     */
+    fun removeNotification(key: String, releaseImmediately: Boolean): Boolean
+
+    /**
+     * Try to remove the notification. May not succeed if the notification has not been shown long
+     * enough and needs to be kept around.
+     *
+     * @param key the key of the notification to remove
+     * @param releaseImmediately force a remove regardless of earliest removal time
+     * @param animate if true, animate the removal
+     * @return true if notification is removed, false otherwise
+     */
+    fun removeNotification(key: String, releaseImmediately: Boolean, animate: Boolean): Boolean
+
+    /** Clears all managed notifications. */
+    fun releaseAllImmediately()
+
+    fun setAnimationStateHandler(handler: AnimationStateHandler)
+
+    /**
+     * Set an entry to be expanded and therefore stick in the heads up area if it's pinned until
+     * it's collapsed again.
+     */
+    fun setExpanded(entry: NotificationEntry, expanded: Boolean)
+
+    /**
+     * Sets whether an entry's guts are exposed and therefore it should stick in the heads up area
+     * if it's pinned until it's hidden again.
+     */
+    fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean)
+
+    /**
+     * Set that we are exiting the headsUp pinned mode, but some notifications might still be
+     * animating out. This is used to keep the touchable regions in a reasonable state.
+     */
+    fun setHeadsUpGoingAway(headsUpGoingAway: Boolean)
+
+    /**
+     * Notifies that a remote input textbox in notification gets active or inactive.
+     *
+     * @param entry The entry of the target notification.
+     * @param remoteInputActive True to notify active, False to notify inactive.
+     */
+    fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean)
+
+    fun setTrackingHeadsUp(tracking: Boolean)
+
+    /** Sets the current user. */
+    fun setUser(user: Int)
+
+    /**
+     * Notes that the user took an action on an entry that might indirectly cause the system or the
+     * app to remove the notification.
+     *
+     * @param entry the entry that might be indirectly removed by the user's action
+     * @see
+     *   com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator.mActionPressListener
+     * @see .canRemoveImmediately
+     */
+    fun setUserActionMayIndirectlyRemove(entry: NotificationEntry)
+
+    /**
+     * Decides whether a click is invalid for a notification, i.e. it has not been shown long enough
+     * that a user might have consciously clicked on it.
+     *
+     * @param key the key of the touched notification
+     * @return whether the touch is invalid and should be discarded
+     */
+    fun shouldSwallowClick(key: String): Boolean
+
+    /**
+     * Called when posting a new notification that should alert the user and appear on screen. Adds
+     * the notification to be managed.
+     *
+     * @param entry entry to show
+     */
+    fun showNotification(entry: NotificationEntry)
+
+    fun snooze()
+
+    /**
+     * Unpins all pinned Heads Up Notifications.
+     *
+     * @param userUnPinned The unpinned action is trigger by user real operation.
+     */
+    fun unpinAll(userUnPinned: Boolean)
+
+    fun updateNotification(key: String, alert: Boolean)
+}
+
+/** Sets the animation state of the HeadsUpManager. */
+interface AnimationStateHandler {
+    fun setHeadsUpGoingAwayAnimationsAllowed(allowed: Boolean)
+}
+
+/** Listener to register for HeadsUpNotification Phone changes. */
+interface OnHeadsUpPhoneListenerChange {
+    /**
+     * Called when a heads up notification is 'going away' or no longer 'going away'. See
+     * [HeadsUpManager.setHeadsUpGoingAway].
+     */
+    fun onHeadsUpGoingAwayStateChanged(headsUpGoingAway: Boolean)
+}
+
+/* No op impl of HeadsUpManager. */
+class HeadsUpManagerEmptyImpl @Inject constructor() : HeadsUpManager {
+    override val allEntries = Stream.empty<NotificationEntry>()
+    override fun addHeadsUpPhoneListener(listener: OnHeadsUpPhoneListenerChange) {}
+    override fun addListener(listener: OnHeadsUpChangedListener) {}
+    override fun addSwipedOutNotification(key: String) {}
+    override fun canRemoveImmediately(key: String) = false
+    override fun compare(a: NotificationEntry?, b: NotificationEntry?) = 0
+    override fun dump(pw: PrintWriter, args: Array<out String>) {}
+    override fun extendHeadsUp() {}
+    override fun getEarliestRemovalTime(key: String?) = 0L
+    override fun getTouchableRegion(): Region? = null
+    override fun getTopEntry() = null
+    override fun hasPinnedHeadsUp() = false
+    override fun isAlerting(key: String) = false
+    override fun isHeadsUpGoingAway() = false
+    override fun isSnoozed(packageName: String) = false
+    override fun isSticky(key: String?) = false
+    override fun isTrackingHeadsUp() = false
+    override fun onExpandingFinished() {}
+    override fun releaseAllImmediately() {}
+    override fun removeListener(listener: OnHeadsUpChangedListener) {}
+    override fun removeNotification(key: String, releaseImmediately: Boolean) = false
+    override fun removeNotification(key: String, releaseImmediately: Boolean, animate: Boolean) =
+        false
+    override fun setAnimationStateHandler(handler: AnimationStateHandler) {}
+    override fun setExpanded(entry: NotificationEntry, expanded: Boolean) {}
+    override fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean) {}
+    override fun setHeadsUpGoingAway(headsUpGoingAway: Boolean) {}
+    override fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean) {}
+    override fun setTrackingHeadsUp(tracking: Boolean) {}
+    override fun setUser(user: Int) {}
+    override fun setUserActionMayIndirectlyRemove(entry: NotificationEntry) {}
+    override fun shouldSwallowClick(key: String): Boolean = false
+    override fun showNotification(entry: NotificationEntry) {}
+    override fun snooze() {}
+    override fun unpinAll(userUnPinned: Boolean) {}
+    override fun updateNotification(key: String, alert: Boolean) {}
+}
+
+@Module
+interface HeadsUpEmptyImplModule {
+    @Binds @SysUISingleton fun bindsHeadsUpManager(noOpHum: HeadsUpManagerEmptyImpl): HeadsUpManager
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt
index c302d6a..859e636 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt
@@ -17,6 +17,7 @@
 
 import android.content.res.Resources
 import com.android.systemui.res.R
+import javax.inject.Inject
 
 /**
  * Fake SplitShadeStateController
@@ -24,7 +25,7 @@
  * Identical behaviour to legacy implementation (that used LargeScreenUtils.kt) I.E., behaviour
  * based solely on resources, no extra flag logic.
  */
-class ResourcesSplitShadeStateController : SplitShadeStateController {
+class ResourcesSplitShadeStateController @Inject constructor() : SplitShadeStateController {
     override fun shouldUseSplitNotificationShade(resources: Resources): Boolean {
         return resources.getBoolean(R.bool.config_use_split_notification_shade)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index a77c692..818ba95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -70,6 +70,7 @@
 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepository;
 import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepositoryImpl;
+import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepositoryModule;
 
 import dagger.Binds;
 import dagger.Module;
@@ -80,7 +81,7 @@
 import javax.inject.Named;
 
 /** Dagger Module for code in the statusbar.policy package. */
-@Module
+@Module(includes = { DeviceProvisioningRepositoryModule.class })
 public interface StatusBarPolicyModule {
 
     String DEVICE_STATE_ROTATION_LOCK_DEFAULTS = "DEVICE_STATE_ROTATION_LOCK_DEFAULTS";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt
new file mode 100644
index 0000000..1160d65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy.data.repository
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Tracks state related to device provisioning. */
+interface DeviceProvisioningRepository {
+    /**
+     * Whether this device has been provisioned.
+     *
+     * @see android.provider.Settings.Global.DEVICE_PROVISIONED
+     */
+    val isDeviceProvisioned: Flow<Boolean>
+
+    /** Whether Factory Reset Protection (FRP) is currently active, locking the device. */
+    val isFactoryResetProtectionActive: Flow<Boolean>
+}
+
+@Module
+interface DeviceProvisioningRepositoryModule {
+    @Binds fun bindsImpl(impl: DeviceProvisioningRepositoryImpl): DeviceProvisioningRepository
+}
+
+class DeviceProvisioningRepositoryImpl
+@Inject
+constructor(
+    private val deviceProvisionedController: DeviceProvisionedController,
+) : DeviceProvisioningRepository {
+
+    override val isDeviceProvisioned: Flow<Boolean> = conflatedCallbackFlow {
+        val listener =
+            object : DeviceProvisionedController.DeviceProvisionedListener {
+                override fun onDeviceProvisionedChanged() {
+                    trySend(deviceProvisionedController.isDeviceProvisioned)
+                }
+            }
+        deviceProvisionedController.addCallback(listener)
+        trySend(deviceProvisionedController.isDeviceProvisioned)
+        awaitClose { deviceProvisionedController.removeCallback(listener) }
+    }
+
+    override val isFactoryResetProtectionActive: Flow<Boolean> = conflatedCallbackFlow {
+        val listener =
+            object : DeviceProvisionedController.DeviceProvisionedListener {
+                override fun onFrpActiveChanged() {
+                    trySend(deviceProvisionedController.isFrpActive)
+                }
+            }
+        deviceProvisionedController.addCallback(listener)
+        trySend(deviceProvisionedController.isFrpActive)
+        awaitClose { deviceProvisionedController.removeCallback(listener) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ui/binder/KeyguardStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ui/binder/KeyguardStatusBarViewBinder.kt
index c63ef9e..6988e21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ui/binder/KeyguardStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ui/binder/KeyguardStatusBarViewBinder.kt
@@ -22,6 +22,8 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView
 import com.android.systemui.statusbar.ui.viewmodel.KeyguardStatusBarViewModel
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.launch
 
 /** Binds [KeyguardStatusBarViewModel] to [KeyguardStatusBarView]. */
 object KeyguardStatusBarViewBinder {
@@ -32,8 +34,18 @@
     ) {
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
-                viewModel.isVisible.collect { isVisible ->
-                    view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
+                launch {
+                    viewModel.isVisible.collect { isVisible ->
+                        view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
+                    }
+                }
+
+                launch { viewModel.isBatteryCharging.collect { view.onBatteryChargingChanged(it) } }
+
+                launch {
+                    viewModel.isKeyguardUserSwitcherEnabled.distinctUntilChanged().collect {
+                        view.setKeyguardUserSwitcherEnabled(it)
+                    }
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
index ddfed87..5da01e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
@@ -16,12 +16,18 @@
 
 package com.android.systemui.statusbar.ui.viewmodel
 
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.statusbar.domain.interactor.KeyguardStatusBarInteractor
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
@@ -41,6 +47,8 @@
 constructor(
     @Application scope: CoroutineScope,
     keyguardInteractor: KeyguardInteractor,
+    keyguardStatusBarInteractor: KeyguardStatusBarInteractor,
+    batteryController: BatteryController,
 ) {
     /** True if this view should be visible and false otherwise. */
     val isVisible: StateFlow<Boolean> =
@@ -51,4 +59,26 @@
                 !isDozing && statusBarState == StatusBarState.KEYGUARD
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    /** True if the device's battery is currently charging and false otherwise. */
+    // Note: Never make this an eagerly-started state flow so that the callback is removed when the
+    // keyguard status bar view isn't attached.
+    val isBatteryCharging: Flow<Boolean> = conflatedCallbackFlow {
+        val callback =
+            object : BatteryStateChangeCallback {
+                override fun onBatteryLevelChanged(
+                    level: Int,
+                    pluggedIn: Boolean,
+                    charging: Boolean,
+                ) {
+                    trySend(charging)
+                }
+            }
+        batteryController.addCallback(callback)
+        awaitClose { batteryController.removeCallback(callback) }
+    }
+
+    /** True if we can show the user switcher on keyguard and false otherwise. */
+    val isKeyguardUserSwitcherEnabled: Flow<Boolean> =
+        keyguardStatusBarInteractor.isKeyguardUserSwitcherEnabled
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index f404549..5fc435a 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -23,7 +23,6 @@
 import android.os.UserManager
 import android.provider.Settings
 import androidx.annotation.VisibleForTesting
-import com.android.systemui.res.R
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
@@ -31,6 +30,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.user.data.model.SelectedUserModel
 import com.android.systemui.user.data.model.SelectionStatus
@@ -132,7 +132,6 @@
                         Settings.Global.ADD_USERS_WHEN_LOCKED,
                         Settings.Global.USER_SWITCHER_ENABLED,
                     ),
-                userId = UserHandle.USER_SYSTEM,
             )
             .onStart { emit(Unit) } // Forces an initial update.
             .map { getSettings() }
@@ -247,7 +246,7 @@
     private suspend fun getSettings(): UserSwitcherSettingsModel {
         return withContext(backgroundDispatcher) {
             val isSimpleUserSwitcher =
-                globalSettings.getIntForUser(
+                globalSettings.getInt(
                     SETTING_SIMPLE_USER_SWITCHER,
                     if (
                         appContext.resources.getBoolean(
@@ -258,18 +257,16 @@
                     } else {
                         0
                     },
-                    UserHandle.USER_SYSTEM,
                 ) != 0
 
             val isAddUsersFromLockscreen =
-                globalSettings.getIntForUser(
+                globalSettings.getInt(
                     Settings.Global.ADD_USERS_WHEN_LOCKED,
                     0,
-                    UserHandle.USER_SYSTEM,
                 ) != 0
 
             val isUserSwitcherEnabled =
-                globalSettings.getIntForUser(
+                globalSettings.getInt(
                     Settings.Global.USER_SWITCHER_ENABLED,
                     if (
                         appContext.resources.getBoolean(
@@ -280,7 +277,6 @@
                     } else {
                         0
                     },
-                    UserHandle.USER_SYSTEM,
                 ) != 0
 
             UserSwitcherSettingsModel(
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
index 18ae107..71352ef 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
@@ -23,4 +23,6 @@
 @Module
 interface UserRepositoryModule {
     @Binds fun bindRepository(impl: UserRepositoryImpl): UserRepository
+
+    @Binds fun userSwitcherRepository(impl: UserSwitcherRepositoryImpl): UserSwitcherRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/data/repository/UserSwitcherRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserSwitcherRepository.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/qs/footer/data/repository/UserSwitcherRepository.kt
rename to packages/SystemUI/src/com/android/systemui/user/data/repository/UserSwitcherRepository.kt
index 5fa75ad..dc7fadd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/data/repository/UserSwitcherRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserSwitcherRepository.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.footer.data.repository
+package com.android.systemui.user.data.repository
 
 import android.content.Context
 import android.graphics.drawable.Drawable
@@ -22,7 +22,6 @@
 import android.os.UserManager
 import android.provider.Settings.Global.USER_SWITCHER_ENABLED
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.res.R
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
@@ -30,6 +29,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.qs.SettingObserver
 import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.UserInfoController
 import com.android.systemui.statusbar.policy.UserSwitcherController
@@ -48,6 +48,9 @@
 interface UserSwitcherRepository {
     /** The current [UserSwitcherStatusModel]. */
     val userSwitcherStatus: Flow<UserSwitcherStatusModel>
+
+    /** Whether the user switcher is currently enabled. */
+    val isEnabled: Flow<Boolean>
 }
 
 @SysUISingleton
@@ -66,8 +69,7 @@
     private val showUserSwitcherForSingleUser =
         context.resources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)
 
-    /** Whether the user switcher is currently enabled. */
-    private val isEnabled: Flow<Boolean> = conflatedCallbackFlow {
+    override val isEnabled: Flow<Boolean> = conflatedCallbackFlow {
         suspend fun updateState() {
             trySendWithFailureLogging(isUserSwitcherEnabled(), TAG)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index ce9d6fd..dbc3bf3 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -325,6 +325,7 @@
                             addAction(Intent.ACTION_USER_SWITCHED)
                             addAction(Intent.ACTION_USER_STOPPED)
                             addAction(Intent.ACTION_USER_UNLOCKED)
+                            addAction(Intent.ACTION_LOCALE_CHANGED)
                         },
                     user = UserHandle.SYSTEM,
                     map = { intent, _ -> intent },
@@ -615,6 +616,7 @@
     ) {
         val shouldRefreshAllUsers =
             when (intent.action) {
+                Intent.ACTION_LOCALE_CHANGED -> true
                 Intent.ACTION_USER_SWITCHED -> {
                     dismissDialog()
                     val selectedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
@@ -644,6 +646,11 @@
     }
 
     private fun restartSecondaryService(@UserIdInt userId: Int) {
+        // Do not start service for user that is marked for deletion.
+        if (!manager.aliveUsers.map { it.id }.contains(userId)) {
+            return
+        }
+
         val intent = Intent(applicationContext, SystemUISecondaryUserService::class.java)
         // Disconnect from the old secondary user's service
         val secondaryUserId = repository.secondaryUserId
@@ -657,6 +664,7 @@
 
         // Connect to the new secondary user's service (purely to ensure that a persistent
         // SystemUI application is created for that user)
+
         if (userId != Process.myUserHandle().identifier) {
             applicationContext.startServiceAsUser(
                 intent,
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
index d3f83b1..20f0fa8c 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -68,6 +68,7 @@
 
     private val hasCancelButtonBeenClicked = MutableStateFlow(false)
     private val isFinishRequiredDueToExecutedAction = MutableStateFlow(false)
+    private val userSwitched = MutableStateFlow(false)
 
     /**
      * Whether the observer should finish the experience. Once consumed, [onFinished] must be called
@@ -89,6 +90,7 @@
     fun onFinished() {
         hasCancelButtonBeenClicked.value = false
         isFinishRequiredDueToExecutedAction.value = false
+        userSwitched.value = false
     }
 
     /** Notifies that the user has clicked the "open menu" button. */
@@ -121,8 +123,9 @@
             hasCancelButtonBeenClicked,
             // If an executed action told us to finish, we should finish,
             isFinishRequiredDueToExecutedAction,
-        ) { cancelButtonClicked, executedActionFinish ->
-            cancelButtonClicked || executedActionFinish
+            userSwitched,
+        ) { cancelButtonClicked, executedActionFinish, userSwitched ->
+            cancelButtonClicked || executedActionFinish || userSwitched
         }
 
     private fun toViewModel(
@@ -191,7 +194,10 @@
         return if (!model.isSelectable) {
             null
         } else {
-            { userInteractor.selectUser(model.id) }
+            {
+                userInteractor.selectUser(model.id)
+                userSwitched.value = true
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt b/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt
new file mode 100644
index 0000000..ac04d31
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt
@@ -0,0 +1,50 @@
+package com.android.systemui.util
+
+import java.lang.ref.SoftReference
+import java.lang.ref.WeakReference
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+
+/**
+ * Creates a Kotlin idiomatic weak reference.
+ *
+ * Usage:
+ * ```
+ * var weakReferenceObj: Object? by weakReference(null)
+ * weakReferenceObj = Object()
+ * ```
+ */
+fun <T> weakReference(obj: T? = null): ReadWriteProperty<Any?, T?> {
+    return object : ReadWriteProperty<Any?, T?> {
+        var weakRef = WeakReference<T?>(obj)
+        override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
+            return weakRef.get()
+        }
+
+        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
+            weakRef = WeakReference(value)
+        }
+    }
+}
+
+/**
+ * Creates a Kotlin idiomatic soft reference.
+ *
+ * Usage:
+ * ```
+ * var softReferenceObj: Object? by softReference(null)
+ * softReferenceObj = Object()
+ * ```
+ */
+fun <T> softReference(obj: T? = null): ReadWriteProperty<Any?, T?> {
+    return object : ReadWriteProperty<Any?, T?> {
+        var softRef = SoftReference<T?>(obj)
+        override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
+            return softRef.get()
+        }
+
+        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
+            softRef = SoftReference(value)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
index 47d505e..83ff789 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -18,19 +18,24 @@
 
 import com.android.systemui.util.time.SystemClock
 import com.android.systemui.util.time.SystemClockImpl
-import kotlinx.coroutines.CoroutineStart
 import java.util.concurrent.atomic.AtomicReference
+import kotlin.math.max
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.channelFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
-import kotlin.math.max
 
 /**
  * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
@@ -44,8 +49,7 @@
     var previousValue: Any? = noVal
     collect { newVal ->
         if (previousValue != noVal) {
-            @Suppress("UNCHECKED_CAST")
-            emit(transform(previousValue as T, newVal))
+            @Suppress("UNCHECKED_CAST") emit(transform(previousValue as T, newVal))
         }
         previousValue = newVal
     }
@@ -60,13 +64,11 @@
 fun <T, R> Flow<T>.pairwiseBy(
     initialValue: T,
     transform: suspend (previousValue: T, newValue: T) -> R,
-): Flow<R> =
-    onStart { emit(initialValue) }.pairwiseBy(transform)
+): Flow<R> = onStart { emit(initialValue) }.pairwiseBy(transform)
 
 /**
  * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
  *
- *
  * The output of [getInitialValue] will be used as the "old" value for the first emission. As
  * opposed to the initial value in the above [pairwiseBy], [getInitialValue] can do some work before
  * returning the initial value.
@@ -76,8 +78,7 @@
 fun <T, R> Flow<T>.pairwiseBy(
     getInitialValue: suspend () -> T,
     transform: suspend (previousValue: T, newValue: T) -> R,
-): Flow<R> =
-    onStart { emit(getInitialValue()) }.pairwiseBy(transform)
+): Flow<R> = onStart { emit(getInitialValue()) }.pairwiseBy(transform)
 
 /**
  * Returns a new [Flow] that produces the two most recent emissions from [this]. Note that the new
@@ -88,8 +89,8 @@
 fun <T> Flow<T>.pairwise(): Flow<WithPrev<T>> = pairwiseBy(::WithPrev)
 
 /**
- * Returns a new [Flow] that produces the two most recent emissions from [this]. [initialValue]
- * will be used as the "old" value for the first emission.
+ * Returns a new [Flow] that produces the two most recent emissions from [this]. [initialValue] will
+ * be used as the "old" value for the first emission.
  *
  * Useful for code that needs to compare the current value to the previous value.
  */
@@ -102,9 +103,9 @@
  * Returns a new [Flow] that combines the [Set] changes between each emission from [this] using
  * [transform].
  *
- * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
- * a change event to be emitted that contains no removals, and all elements from that first [Set]
- * as additions.
+ * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause a
+ * change event to be emitted that contains no removals, and all elements from that first [Set] as
+ * additions.
  *
  * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
  * until a second [Set] has been emitted from the upstream [Flow].
@@ -112,22 +113,23 @@
 fun <T, R> Flow<Set<T>>.setChangesBy(
     transform: suspend (removed: Set<T>, added: Set<T>) -> R,
     emitFirstEvent: Boolean = true,
-): Flow<R> = (if (emitFirstEvent) onStart { emit(emptySet()) } else this)
-    .distinctUntilChanged()
-    .pairwiseBy { old: Set<T>, new: Set<T> ->
-        // If an element was present in the old set, but not the new one, then it was removed
-        val removed = old - new
-        // If an element is present in the new set, but on the old one, then it was added
-        val added = new - old
-        transform(removed, added)
-    }
+): Flow<R> =
+    (if (emitFirstEvent) onStart { emit(emptySet()) } else this)
+        .distinctUntilChanged()
+        .pairwiseBy { old: Set<T>, new: Set<T> ->
+            // If an element was present in the old set, but not the new one, then it was removed
+            val removed = old - new
+            // If an element is present in the new set, but on the old one, then it was added
+            val added = new - old
+            transform(removed, added)
+        }
 
 /**
  * Returns a new [Flow] that produces the [Set] changes between each emission from [this].
  *
- * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
- * a change event to be emitted that contains no removals, and all elements from that first [Set]
- * as additions.
+ * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause a
+ * change event to be emitted that contains no removals, and all elements from that first [Set] as
+ * additions.
  *
  * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
  * until a second [Set] has been emitted from the upstream [Flow].
@@ -153,14 +155,11 @@
     coroutineScope {
         val noVal = Any()
         val sampledRef = AtomicReference(noVal)
-        val job = launch(Dispatchers.Unconfined) {
-            other.collect { sampledRef.set(it) }
-        }
+        val job = launch(Dispatchers.Unconfined) { other.collect { sampledRef.set(it) } }
         collect {
             val sampled = sampledRef.get()
             if (sampled != noVal) {
-                @Suppress("UNCHECKED_CAST")
-                emit(transform(it, sampled as B))
+                @Suppress("UNCHECKED_CAST") emit(transform(it, sampled as B))
             }
         }
         job.cancel()
@@ -181,7 +180,6 @@
  * latest value is emitted.
  *
  * Example:
- *
  * ```kotlin
  * flow {
  *     emit(1)     // t=0ms
@@ -210,7 +208,6 @@
  * during this period, only The latest value is emitted.
  *
  * Example:
- *
  * ```kotlin
  * flow {
  *     emit(1)     // t=0ms
@@ -248,10 +245,11 @@
                 // We create delayJob to allow cancellation during the delay period
                 delayJob = launch {
                     delay(timeUntilNextEmit)
-                    sendJob = outerScope.launch(start = CoroutineStart.UNDISPATCHED) {
-                        send(it)
-                        previousEmitTimeMs = clock.elapsedRealtime()
-                    }
+                    sendJob =
+                        outerScope.launch(start = CoroutineStart.UNDISPATCHED) {
+                            send(it)
+                            previousEmitTimeMs = clock.elapsedRealtime()
+                        }
                 }
             } else {
                 send(it)
@@ -259,4 +257,15 @@
             }
         }
     }
-}
\ No newline at end of file
+}
+
+/**
+ * Returns a [StateFlow] launched in the surrounding [CoroutineScope]. This [StateFlow] gets its
+ * value by invoking [getValue] whenever an event is emitted from [changedSignals]. It will also
+ * immediately invoke [getValue] to establish its initial value.
+ */
+inline fun <T> CoroutineScope.stateFlow(
+    changedSignals: Flow<Unit>,
+    crossinline getValue: () -> T,
+): StateFlow<T> =
+    changedSignals.map { getValue() }.stateIn(this, SharingStarted.Eagerly, getValue())
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
index 85fada2..42389f0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
@@ -16,22 +16,23 @@
 
 package com.android.systemui.util.settings;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.content.ContentResolver;
 import android.net.Uri;
 import android.provider.Settings;
 
-import com.android.systemui.settings.UserTracker;
-
 import javax.inject.Inject;
 
+// use UserHandle.USER_SYSTEM everywhere
+@SuppressLint("StaticSettingsProvider")
 class GlobalSettingsImpl implements GlobalSettings {
     private final ContentResolver mContentResolver;
-    private final UserTracker mUserTracker;
 
     @Inject
-    GlobalSettingsImpl(ContentResolver contentResolver, UserTracker userTracker) {
+    GlobalSettingsImpl(ContentResolver contentResolver) {
         mContentResolver = contentResolver;
-        mUserTracker = userTracker;
     }
 
     @Override
@@ -40,43 +41,23 @@
     }
 
     @Override
-    public UserTracker getUserTracker() {
-        return mUserTracker;
-    }
-
-    @Override
     public Uri getUriFor(String name) {
         return Settings.Global.getUriFor(name);
     }
 
     @Override
-    public String getStringForUser(String name, int userHandle) {
-        return Settings.Global.getStringForUser(mContentResolver, name,
-                getRealUserHandle(userHandle));
+    public String getString(String name) {
+        return Settings.Global.getString(mContentResolver, name);
     }
 
     @Override
-    public boolean putString(String name, String value, boolean overrideableByRestore) {
-        throw new UnsupportedOperationException(
-                "This method only exists publicly for Settings.System and Settings.Secure");
+    public boolean putString(String name, String value) {
+        return Settings.Global.putString(mContentResolver, name, value);
     }
 
     @Override
-    public boolean putStringForUser(String name, String value, int userHandle) {
-        return Settings.Global.putStringForUser(mContentResolver, name, value,
-                getRealUserHandle(userHandle));
-    }
-
-    @Override
-    public boolean putStringForUser(String name, String value, String tag, boolean makeDefault,
-            int userHandle, boolean overrideableByRestore) {
-        return Settings.Global.putStringForUser(
-                mContentResolver, name, value, tag, makeDefault, getRealUserHandle(userHandle),
-                overrideableByRestore);
-    }
-
-    @Override
-    public boolean putString(String name, String value, String tag, boolean makeDefault) {
+    public boolean putString(@NonNull String name, @Nullable String value, @Nullable String tag,
+            boolean makeDefault) {
         return Settings.Global.putString(mContentResolver, name, value, tag, makeDefault);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java
index 798033e..6031a4e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java
@@ -22,5 +22,5 @@
  * See {@link SettingsProxy} for details.
  */
 
-public interface SecureSettings extends SettingsProxy {
+public interface SecureSettings extends UserSettingsProxy {
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
index f995436..6532ce8 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
@@ -20,6 +20,8 @@
 import android.net.Uri;
 import android.provider.Settings;
 
+import androidx.annotation.NonNull;
+
 import com.android.systemui.settings.UserTracker;
 
 import javax.inject.Inject;
@@ -75,7 +77,7 @@
     }
 
     @Override
-    public boolean putString(String name, String value, String tag, boolean makeDefault) {
+    public boolean putString(@NonNull String name, String value, String tag, boolean makeDefault) {
         return Settings.Secure.putString(mContentResolver, name, value, tag, makeDefault);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
index b6846a3..6a9edc1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
@@ -18,25 +18,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.content.ContentResolver;
 import android.database.ContentObserver;
 import android.net.Uri;
-import android.os.UserHandle;
 import android.provider.Settings;
 
-import com.android.systemui.settings.UserTracker;
-
 /**
- * Used to interact with Settings.Secure, Settings.Global, and Settings.System.
- *
+ * Used to interact with mainly with Settings.Global, but can also be used for Settings.System
+ * and Settings.Secure. To use the per-user System and Secure settings, {@link UserSettingsProxy}
+ * must be used instead.
+ * <p>
  * This interface can be implemented to give instance method (instead of static method) versions
- * of Settings.Secure, Settings.Global, and Settings.System. It can be injected into class
- * constructors and then faked or mocked as needed in tests.
- *
- * You can ask for {@link SecureSettings}, {@link GlobalSettings}, or {@link SystemSettings} to be
- * injected as needed.
- *
+ * of Settings.Global. It can be injected into class constructors and then faked or mocked as needed
+ * in tests.
+ * <p>
+ * You can ask for {@link GlobalSettings} to be injected as needed.
+ * <p>
  * This class also provides {@link #registerContentObserver(String, ContentObserver)} methods,
  * normally found on {@link ContentResolver} instances, unifying setting related actions in one
  * place.
@@ -49,29 +46,6 @@
     ContentResolver getContentResolver();
 
     /**
-     * Returns that {@link UserTracker} this instance was constructed with.
-     */
-    UserTracker getUserTracker();
-
-    /**
-     * Returns the user id for the associated {@link ContentResolver}.
-     */
-    default int getUserId() {
-        return getContentResolver().getUserId();
-    }
-
-    /**
-     * Returns the actual current user handle when querying with the current user. Otherwise,
-     * returns the passed in user id.
-     */
-    default int getRealUserHandle(int userHandle) {
-        if (userHandle != UserHandle.USER_CURRENT) {
-            return userHandle;
-        }
-        return getUserTracker().getUserId();
-    }
-
-    /**
      * Construct the content URI for a particular name/value pair,
      * useful for monitoring changes with a ContentObserver.
      * @param name to look up in the table
@@ -82,7 +56,7 @@
     /**
      * Convenience wrapper around
      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
-     *
+     * <p>
      * Implicitly calls {@link #getUriFor(String)} on the passed in name.
      */
     default void registerContentObserver(String name, ContentObserver settingsObserver) {
@@ -94,13 +68,13 @@
      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
      */
     default void registerContentObserver(Uri uri, ContentObserver settingsObserver) {
-        registerContentObserverForUser(uri, settingsObserver, getUserId());
+        registerContentObserver(uri, false, settingsObserver);
     }
 
     /**
      * Convenience wrapper around
      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
-     *
+     * <p>
      * Implicitly calls {@link #getUriFor(String)} on the passed in name.
      */
     default void registerContentObserver(String name, boolean notifyForDescendants,
@@ -114,53 +88,8 @@
      */
     default void registerContentObserver(Uri uri, boolean notifyForDescendants,
             ContentObserver settingsObserver) {
-        registerContentObserverForUser(uri, notifyForDescendants, settingsObserver, getUserId());
-    }
-
-    /**
-     * Convenience wrapper around
-     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
-     *
-     * Implicitly calls {@link #getUriFor(String)} on the passed in name.
-     */
-    default void registerContentObserverForUser(
-            String name, ContentObserver settingsObserver, int userHandle) {
-        registerContentObserverForUser(
-                getUriFor(name), settingsObserver, userHandle);
-    }
-
-    /**
-     * Convenience wrapper around
-     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
-     */
-    default void registerContentObserverForUser(
-            Uri uri, ContentObserver settingsObserver, int userHandle) {
-        registerContentObserverForUser(
-                uri, false, settingsObserver, userHandle);
-    }
-
-    /**
-     * Convenience wrapper around
-     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
-     *
-     * Implicitly calls {@link #getUriFor(String)} on the passed in name.
-     */
-    default void registerContentObserverForUser(
-            String name, boolean notifyForDescendants, ContentObserver settingsObserver,
-            int userHandle) {
-        registerContentObserverForUser(
-                getUriFor(name), notifyForDescendants, settingsObserver, userHandle);
-    }
-
-    /**
-     * Convenience wrapper around
-     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
-     */
-    default void registerContentObserverForUser(
-            Uri uri, boolean notifyForDescendants, ContentObserver settingsObserver,
-            int userHandle) {
         getContentResolver().registerContentObserver(
-                uri, notifyForDescendants, settingsObserver, getRealUserHandle(userHandle));
+                uri, notifyForDescendants, settingsObserver);
     }
 
     /** See {@link ContentResolver#unregisterContentObserver(ContentObserver)}. */
@@ -173,22 +102,7 @@
      * @param name to look up in the table
      * @return the corresponding value, or null if not present
      */
-    default String getString(String name) {
-        return getStringForUser(name, getUserId());
-    }
-
-    /**See {@link #getString(String)}. */
-    String getStringForUser(String name, int userHandle);
-
-    /**
-     * Store a name/value pair into the database. Values written by this method will be
-     * overridden if a restore happens in the future.
-     *
-     * @param name to store
-     * @param value to associate with the name
-     * @return true if the value was set, false on database errors
-     */
-    boolean putString(String name, String value, boolean overrideableByRestore);
+    String getString(String name);
 
     /**
      * Store a name/value pair into the database.
@@ -196,16 +110,7 @@
      * @param value to associate with the name
      * @return true if the value was set, false on database errors
      */
-    default boolean putString(String name, String value) {
-        return putStringForUser(name, value, getUserId());
-    }
-
-    /** See {@link #putString(String, String)}. */
-    boolean putStringForUser(String name, String value, int userHandle);
-
-    /** See {@link #putString(String, String)}. */
-    boolean putStringForUser(@NonNull String name, @Nullable String value, @Nullable String tag,
-            boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore);
+    boolean putString(String name, String value);
 
     /**
      * Store a name/value pair into the database.
@@ -262,12 +167,7 @@
      * or not a valid integer.
      */
     default int getInt(String name, int def) {
-        return getIntForUser(name, def, getUserId());
-    }
-
-    /** See {@link #getInt(String, int)}. */
-    default int getIntForUser(String name, int def, int userHandle) {
-        String v = getStringForUser(name, userHandle);
+        String v = getString(name);
         try {
             return v != null ? Integer.parseInt(v) : def;
         } catch (NumberFormatException e) {
@@ -292,14 +192,9 @@
      *
      * @return The setting's current value.
      */
-    default int getInt(String name) throws Settings.SettingNotFoundException {
-        return getIntForUser(name, getUserId());
-    }
-
-    /** See {@link #getInt(String)}. */
-    default int getIntForUser(String name, int userHandle)
+    default int getInt(String name)
             throws Settings.SettingNotFoundException {
-        String v = getStringForUser(name, userHandle);
+        String v = getString(name);
         try {
             return Integer.parseInt(v);
         } catch (NumberFormatException e) {
@@ -320,12 +215,7 @@
      * @return true if the value was set, false on database errors
      */
     default boolean putInt(String name, int value) {
-        return putIntForUser(name, value, getUserId());
-    }
-
-    /** See {@link #putInt(String, int)}. */
-    default boolean putIntForUser(String name, int value, int userHandle) {
-        return putStringForUser(name, Integer.toString(value), userHandle);
+        return putString(name, Integer.toString(value));
     }
 
     /**
@@ -342,12 +232,7 @@
      * or not a valid boolean.
      */
     default boolean getBool(String name, boolean def) {
-        return getBoolForUser(name, def, getUserId());
-    }
-
-    /** See {@link #getBool(String, boolean)}. */
-    default boolean getBoolForUser(String name, boolean def, int userHandle) {
-        return getIntForUser(name, def ? 1 : 0, userHandle) != 0;
+        return getInt(name, def ? 1 : 0) != 0;
     }
 
     /**
@@ -367,14 +252,9 @@
      *
      * @return The setting's current value.
      */
-    default boolean getBool(String name) throws Settings.SettingNotFoundException {
-        return getBoolForUser(name, getUserId());
-    }
-
-    /** See {@link #getBool(String)}. */
-    default boolean getBoolForUser(String name, int userHandle)
+    default boolean getBool(String name)
             throws Settings.SettingNotFoundException {
-        return getIntForUser(name, userHandle) != 0;
+        return getInt(name) != 0;
     }
 
     /**
@@ -390,12 +270,7 @@
      * @return true if the value was set, false on database errors
      */
     default boolean putBool(String name, boolean value) {
-        return putBoolForUser(name, value, getUserId());
-    }
-
-    /** See {@link #putBool(String, boolean)}. */
-    default boolean putBoolForUser(String name, boolean value, int userHandle) {
-        return putIntForUser(name, value ? 1 : 0, userHandle);
+        return putInt(name, value ? 1 : 0);
     }
 
     /**
@@ -412,12 +287,12 @@
      * or not a valid {@code long}.
      */
     default long getLong(String name, long def) {
-        return getLongForUser(name, def, getUserId());
+        String valString = getString(name);
+        return parseLongOrUseDefault(valString, def);
     }
 
-    /** See {@link #getLong(String, long)}. */
-    default long getLongForUser(String name, long def, int userHandle) {
-        String valString = getStringForUser(name, userHandle);
+    /** Convert a string to a long, or uses a default if the string is malformed or null */
+    static long parseLongOrUseDefault(String valString, long def) {
         long value;
         try {
             value = valString != null ? Long.parseLong(valString) : def;
@@ -443,14 +318,15 @@
      * @throws Settings.SettingNotFoundException Thrown if a setting by the given
      * name can't be found or the setting value is not an integer.
      */
-    default long getLong(String name) throws Settings.SettingNotFoundException {
-        return getLongForUser(name, getUserId());
+    default long getLong(String name)
+            throws Settings.SettingNotFoundException {
+        String valString = getString(name);
+        return parseLongOrThrow(name, valString);
     }
 
-    /** See {@link #getLong(String)}. */
-    default long getLongForUser(String name, int userHandle)
+    /** Convert a string to a long, or throws an exception if the string is malformed or null */
+    static long parseLongOrThrow(String name, String valString)
             throws Settings.SettingNotFoundException {
-        String valString = getStringForUser(name, userHandle);
         try {
             return Long.parseLong(valString);
         } catch (NumberFormatException e) {
@@ -471,12 +347,7 @@
      * @return true if the value was set, false on database errors
      */
     default boolean putLong(String name, long value) {
-        return putLongForUser(name, value, getUserId());
-    }
-
-    /** See {@link #putLong(String, long)}. */
-    default boolean putLongForUser(String name, long value, int userHandle) {
-        return putStringForUser(name, Long.toString(value), userHandle);
+        return putString(name, Long.toString(value));
     }
 
     /**
@@ -493,12 +364,12 @@
      * or not a valid float.
      */
     default float getFloat(String name, float def) {
-        return getFloatForUser(name, def, getUserId());
+        String v = getString(name);
+        return parseFloat(v, def);
     }
 
-    /** See {@link #getFloat(String)}. */
-    default float getFloatForUser(String name, float def, int userHandle) {
-        String v = getStringForUser(name, userHandle);
+    /** Convert a string to a float, or uses a default if the string is malformed or null */
+    static float parseFloat(String v, float def) {
         try {
             return v != null ? Float.parseFloat(v) : def;
         } catch (NumberFormatException e) {
@@ -523,14 +394,15 @@
      *
      * @return The setting's current value.
      */
-    default float getFloat(String name) throws Settings.SettingNotFoundException {
-        return getFloatForUser(name, getUserId());
+    default float getFloat(String name)
+            throws Settings.SettingNotFoundException {
+        String v = getString(name);
+        return parseFloatOrThrow(name, v);
     }
 
-    /** See {@link #getFloat(String, float)}. */
-    default float getFloatForUser(String name, int userHandle)
+    /** Convert a string to a float, or throws an exception if the string is malformed or null */
+    static float parseFloatOrThrow(String name, String v)
             throws Settings.SettingNotFoundException {
-        String v = getStringForUser(name, userHandle);
         if (v == null) {
             throw new Settings.SettingNotFoundException(name);
         }
@@ -554,11 +426,6 @@
      * @return true if the value was set, false on database errors
      */
     default boolean putFloat(String name, float value) {
-        return putFloatForUser(name, value, getUserId());
-    }
-
-    /** See {@link #putFloat(String, float)} */
-    default boolean putFloatForUser(String name, float value, int userHandle) {
-        return putStringForUser(name, Float.toString(value), userHandle);
+        return putString(name, Float.toString(value));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
index 561495e..7484368 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
@@ -27,7 +27,7 @@
 object SettingsProxyExt {
 
     /** Returns a flow of [Unit] that is invoked each time that content is updated. */
-    fun SettingsProxy.observerFlow(
+    fun UserSettingsProxy.observerFlow(
         @UserIdInt userId: Int,
         vararg names: String,
     ): Flow<Unit> {
@@ -44,4 +44,22 @@
             awaitClose { unregisterContentObserver(observer) }
         }
     }
+
+    /** Returns a flow of [Unit] that is invoked each time that content is updated. */
+    fun SettingsProxy.observerFlow(
+        vararg names: String,
+    ): Flow<Unit> {
+        return conflatedCallbackFlow {
+            val observer =
+                object : ContentObserver(null) {
+                    override fun onChange(selfChange: Boolean) {
+                        trySend(Unit)
+                    }
+                }
+
+            names.forEach { name -> registerContentObserver(name, observer) }
+
+            awaitClose { unregisterContentObserver(observer) }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java
index d57d749..c67c603 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java
@@ -21,5 +21,5 @@
  *
  * See {@link SettingsProxy} for details.
  */
-public interface SystemSettings extends SettingsProxy {
+public interface SystemSettings extends UserSettingsProxy {
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
index fba7ddf..658b299 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
@@ -20,6 +20,8 @@
 import android.net.Uri;
 import android.provider.Settings;
 
+import androidx.annotation.NonNull;
+
 import com.android.systemui.settings.UserTracker;
 
 import javax.inject.Inject;
@@ -74,7 +76,7 @@
     }
 
     @Override
-    public boolean putString(String name, String value, String tag, boolean makeDefault) {
+    public boolean putString(@NonNull String name, String value, String tag, boolean makeDefault) {
         throw new UnsupportedOperationException(
                 "This method only exists publicly for Settings.Secure and Settings.Global");
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.java
new file mode 100644
index 0000000..0d6c0f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2023 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.util.settings;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.systemui.settings.UserTracker;
+
+/**
+ * Used to interact with per-user Settings.Secure and Settings.System settings (but not
+ * Settings.Global, since those do not vary per-user)
+ * <p>
+ * This interface can be implemented to give instance method (instead of static method) versions
+ * of Settings.Secure and Settings.System. It can be injected into class constructors and then
+ * faked or mocked as needed in tests.
+ * <p>
+ * You can ask for {@link SecureSettings} or {@link SystemSettings} to be injected as needed.
+ * <p>
+ * This class also provides {@link #registerContentObserver(String, ContentObserver)} methods,
+ * normally found on {@link ContentResolver} instances, unifying setting related actions in one
+ * place.
+ */
+public interface UserSettingsProxy extends SettingsProxy {
+
+    /**
+     * Returns that {@link UserTracker} this instance was constructed with.
+     */
+    UserTracker getUserTracker();
+
+    /**
+     * Returns the user id for the associated {@link ContentResolver}.
+     */
+    default int getUserId() {
+        return getContentResolver().getUserId();
+    }
+
+    /**
+     * Returns the actual current user handle when querying with the current user. Otherwise,
+     * returns the passed in user id.
+     */
+    default int getRealUserHandle(int userHandle) {
+        if (userHandle != UserHandle.USER_CURRENT) {
+            return userHandle;
+        }
+        return getUserTracker().getUserId();
+    }
+
+    @Override
+    default void registerContentObserver(Uri uri, ContentObserver settingsObserver) {
+        registerContentObserverForUser(uri, settingsObserver, getUserId());
+    }
+
+    /**
+     * Convenience wrapper around
+     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
+     */
+    @Override
+    default void registerContentObserver(Uri uri, boolean notifyForDescendants,
+            ContentObserver settingsObserver) {
+        registerContentObserverForUser(uri, notifyForDescendants, settingsObserver, getUserId());
+    }
+
+    /**
+     * Convenience wrapper around
+     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
+     *
+     * Implicitly calls {@link #getUriFor(String)} on the passed in name.
+     */
+    default void registerContentObserverForUser(
+            String name, ContentObserver settingsObserver, int userHandle) {
+        registerContentObserverForUser(
+                getUriFor(name), settingsObserver, userHandle);
+    }
+
+    /**
+     * Convenience wrapper around
+     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
+     */
+    default void registerContentObserverForUser(
+            Uri uri, ContentObserver settingsObserver, int userHandle) {
+        registerContentObserverForUser(
+                uri, false, settingsObserver, userHandle);
+    }
+
+    /**
+     * Convenience wrapper around
+     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
+     *
+     * Implicitly calls {@link #getUriFor(String)} on the passed in name.
+     */
+    default void registerContentObserverForUser(
+            String name, boolean notifyForDescendants, ContentObserver settingsObserver,
+            int userHandle) {
+        registerContentObserverForUser(
+                getUriFor(name), notifyForDescendants, settingsObserver, userHandle);
+    }
+
+    /**
+     * Convenience wrapper around
+     * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
+     */
+    default void registerContentObserverForUser(
+            Uri uri, boolean notifyForDescendants, ContentObserver settingsObserver,
+            int userHandle) {
+        getContentResolver().registerContentObserver(
+                uri, notifyForDescendants, settingsObserver, getRealUserHandle(userHandle));
+    }
+
+    /**
+     * Look up a name in the database.
+     * @param name to look up in the table
+     * @return the corresponding value, or null if not present
+     */
+    @Override
+    default String getString(String name) {
+        return getStringForUser(name, getUserId());
+    }
+
+    /**See {@link #getString(String)}. */
+    String getStringForUser(String name, int userHandle);
+
+    /**
+     * Store a name/value pair into the database. Values written by this method will be
+     * overridden if a restore happens in the future.
+     *
+     * @param name to store
+     * @param value to associate with the name
+     * @return true if the value was set, false on database errors
+     */
+    boolean putString(String name, String value, boolean overrideableByRestore);
+
+    @Override
+    default boolean putString(String name, String value) {
+        return putStringForUser(name, value, getUserId());
+    }
+
+    /** See {@link #putString(String, String)}. */
+    boolean putStringForUser(String name, String value, int userHandle);
+
+    /** See {@link #putString(String, String)}. */
+    boolean putStringForUser(@NonNull String name, @Nullable String value, @Nullable String tag,
+            boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore);
+
+    @Override
+    default int getInt(String name, int def) {
+        return getIntForUser(name, def, getUserId());
+    }
+
+    /** See {@link #getInt(String, int)}. */
+    default int getIntForUser(String name, int def, int userHandle) {
+        String v = getStringForUser(name, userHandle);
+        try {
+            return v != null ? Integer.parseInt(v) : def;
+        } catch (NumberFormatException e) {
+            return def;
+        }
+    }
+
+    @Override
+    default int getInt(String name) throws Settings.SettingNotFoundException {
+        return getIntForUser(name, getUserId());
+    }
+
+    /** See {@link #getInt(String)}. */
+    default int getIntForUser(String name, int userHandle)
+            throws Settings.SettingNotFoundException {
+        String v = getStringForUser(name, userHandle);
+        try {
+            return Integer.parseInt(v);
+        } catch (NumberFormatException e) {
+            throw new Settings.SettingNotFoundException(name);
+        }
+    }
+
+    @Override
+    default boolean putInt(String name, int value) {
+        return putIntForUser(name, value, getUserId());
+    }
+
+    /** See {@link #putInt(String, int)}. */
+    default boolean putIntForUser(String name, int value, int userHandle) {
+        return putStringForUser(name, Integer.toString(value), userHandle);
+    }
+
+    @Override
+    default boolean getBool(String name, boolean def) {
+        return getBoolForUser(name, def, getUserId());
+    }
+
+    /** See {@link #getBool(String, boolean)}. */
+    default boolean getBoolForUser(String name, boolean def, int userHandle) {
+        return getIntForUser(name, def ? 1 : 0, userHandle) != 0;
+    }
+
+    @Override
+    default boolean getBool(String name) throws Settings.SettingNotFoundException {
+        return getBoolForUser(name, getUserId());
+    }
+
+    /** See {@link #getBool(String)}. */
+    default boolean getBoolForUser(String name, int userHandle)
+            throws Settings.SettingNotFoundException {
+        return getIntForUser(name, userHandle) != 0;
+    }
+
+    @Override
+    default boolean putBool(String name, boolean value) {
+        return putBoolForUser(name, value, getUserId());
+    }
+
+    /** See {@link #putBool(String, boolean)}. */
+    default boolean putBoolForUser(String name, boolean value, int userHandle) {
+        return putIntForUser(name, value ? 1 : 0, userHandle);
+    }
+
+    /** See {@link #getLong(String, long)}. */
+    default long getLongForUser(String name, long def, int userHandle) {
+        String valString = getStringForUser(name, userHandle);
+        return SettingsProxy.parseLongOrUseDefault(valString, def);
+    }
+
+    /** See {@link #getLong(String)}. */
+    default long getLongForUser(String name, int userHandle)
+            throws Settings.SettingNotFoundException {
+        String valString = getStringForUser(name, userHandle);
+        return SettingsProxy.parseLongOrThrow(name, valString);
+    }
+
+    /** See {@link #putLong(String, long)}. */
+    default boolean putLongForUser(String name, long value, int userHandle) {
+        return putStringForUser(name, Long.toString(value), userHandle);
+    }
+
+    /** See {@link #getFloat(String)}. */
+    default float getFloatForUser(String name, float def, int userHandle) {
+        String v = getStringForUser(name, userHandle);
+        return SettingsProxy.parseFloat(v, def);
+    }
+
+    /** See {@link #getFloat(String, float)}. */
+    default float getFloatForUser(String name, int userHandle)
+            throws Settings.SettingNotFoundException {
+        String v = getStringForUser(name, userHandle);
+        return SettingsProxy.parseFloatOrThrow(name, v);
+    }
+
+    /** See {@link #putFloat(String, float)} */
+    default boolean putFloatForUser(String name, float value, int userHandle) {
+        return putStringForUser(name, Float.toString(value), userHandle);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt b/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt
new file mode 100644
index 0000000..51d2afa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.util.ui
+
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.firstOrNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.transformLatest
+
+/**
+ * A state comprised of a [value] of type [T] paired with a boolean indicating whether or not the
+ * [value] [isAnimating] in the UI.
+ */
+data class AnimatedValue<T>(
+    val value: T,
+    val isAnimating: Boolean,
+)
+
+/**
+ * An event comprised of a [value] of type [T] paired with a [boolean][startAnimating] indicating
+ * whether or not this event should start an animation.
+ */
+data class AnimatableEvent<T>(
+    val value: T,
+    val startAnimating: Boolean,
+)
+
+/**
+ * Returns a [Flow] that tracks an [AnimatedValue] state. The input [Flow] is used to update the
+ * [AnimatedValue.value], as well as [AnimatedValue.isAnimating] if the event's
+ * [AnimatableEvent.startAnimating] value is `true`. When [completionEvents] emits a value, the
+ * [AnimatedValue.isAnimating] will flip to `false`.
+ */
+fun <T> Flow<AnimatableEvent<T>>.toAnimatedValueFlow(
+    completionEvents: Flow<Any?>,
+): Flow<AnimatedValue<T>> = transformLatest { (value, startAnimating) ->
+    emit(AnimatedValue(value, isAnimating = startAnimating))
+    if (startAnimating) {
+        // Wait for a completion now that we've started animating
+        completionEvents
+            .map { Unit } // replace the event so that it's never `null`
+            .firstOrNull() // `null` indicates an empty flow
+            // emit the new state if the flow was not empty.
+            ?.run { emit(AnimatedValue(value, isAnimating = false)) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index ea4d31b..d65a69c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -77,6 +77,8 @@
 import com.android.systemui.util.RingerModeTracker;
 import com.android.systemui.util.concurrency.ThreadFactory;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import java.io.PrintWriter;
 import java.util.HashMap;
 import java.util.List;
@@ -286,6 +288,7 @@
         return new MediaSessions(context, looper, callbacks);
     }
 
+    @NeverCompile
     public void dump(PrintWriter pw, String[] args) {
         pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
         pw.print("  mVolumePolicy: "); pw.println(mVolumePolicy);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 727d649..929b91c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -135,6 +135,9 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.util.AlphaTintDrawableWrapper;
 import com.android.systemui.util.RoundedCornerProgressDrawable;
+import com.android.systemui.util.settings.SecureSettings;
+
+import dagger.Lazy;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -304,6 +307,8 @@
     private @DevicePostureController.DevicePostureInt int mDevicePosture;
     private int mOrientation;
     private final FeatureFlags mFeatureFlags;
+    private final Lazy<SecureSettings> mSecureSettings;
+    private int mDialogTimeoutMillis;
 
     public VolumeDialogImpl(
             Context context,
@@ -320,7 +325,8 @@
             DevicePostureController devicePostureController,
             Looper looper,
             DumpManager dumpManager,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            Lazy<SecureSettings> secureSettings) {
         mFeatureFlags = featureFlags;
         mContext =
                 new ContextThemeWrapper(context, R.style.volume_dialog_theme);
@@ -351,6 +357,8 @@
         mUseBackgroundBlur =
             mContext.getResources().getBoolean(R.bool.config_volumeDialogUseBackgroundBlur);
         mInteractionJankMonitor = interactionJankMonitor;
+        mSecureSettings = secureSettings;
+        mDialogTimeoutMillis = DIALOG_TIMEOUT_MILLIS;
 
         dumpManager.registerDumpable("VolumeDialogImpl", this);
 
@@ -515,6 +523,8 @@
         mDialog.setContentView(R.layout.volume_dialog);
         mDialogView = mDialog.findViewById(R.id.volume_dialog);
         mDialogView.setAlpha(0);
+        mDialogTimeoutMillis = mSecureSettings.get().getInt(
+                Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, DIALOG_TIMEOUT_MILLIS);
         mDialog.setCanceledOnTouchOutside(true);
         mDialog.setOnShowListener(dialog -> {
             mDialogView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
@@ -527,7 +537,7 @@
                     .alpha(1)
                     .translationX(0)
                     .setDuration(mDialogShowAnimationDurationMs)
-                    .setListener(getJankListener(getDialogView(), TYPE_SHOW, DIALOG_TIMEOUT_MILLIS))
+                    .setListener(getJankListener(getDialogView(), TYPE_SHOW, mDialogTimeoutMillis))
                     .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
                     .withEndAction(() -> {
                         if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) {
@@ -1514,7 +1524,7 @@
                     AccessibilityManager.FLAG_CONTENT_TEXT
                             | AccessibilityManager.FLAG_CONTENT_CONTROLS);
         }
-        return mAccessibilityMgr.getRecommendedTimeoutMillis(DIALOG_TIMEOUT_MILLIS,
+        return mAccessibilityMgr.getRecommendedTimeoutMillis(mDialogTimeoutMillis,
                 AccessibilityManager.FLAG_CONTENT_CONTROLS);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index cc9f3e1..e3b3c21 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.volume.CsdWarningDialog;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.volume.VolumeDialogComponent;
@@ -38,6 +39,7 @@
 import com.android.systemui.volume.VolumePanelFactory;
 
 import dagger.Binds;
+import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
@@ -63,7 +65,8 @@
             CsdWarningDialog.Factory csdFactory,
             DevicePostureController devicePostureController,
             DumpManager dumpManager,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            Lazy<SecureSettings> secureSettings) {
         VolumeDialogImpl impl = new VolumeDialogImpl(
                 context,
                 volumeDialogController,
@@ -79,7 +82,8 @@
                 devicePostureController,
                 Looper.getMainLooper(),
                 dumpManager,
-                featureFlags);
+                featureFlags,
+                secureSettings);
         impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
         impl.setAutomute(true);
         impl.setSilentMode(false);
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index 750b6f9..2132904 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -40,12 +40,13 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -68,6 +69,7 @@
     private final Executor mExecutor;
     private final Handler mHandler;
     private final FalsingManager mFalsingManager;
+    private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
     private FalsingCollector mFalsingCollector;
     private final UserTracker mUserTracker;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -91,7 +93,8 @@
             UserTracker userTracker,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             StatusBarKeyguardViewManager keyguardViewManager,
-            UiEventLogger uiEventLogger) {
+            UiEventLogger uiEventLogger,
+            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor) {
         mKeyguardStateController = keyguardStateController;
         mKeyguardDismissUtil = keyguardDismissUtil;
         mActivityStarter = activityStarter;
@@ -103,6 +106,7 @@
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mKeyguardViewManager = keyguardViewManager;
         mUiEventLogger = uiEventLogger;
+        mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
     }
 
     @Override
@@ -209,6 +213,7 @@
                 true,
                 Utils.getColorAttrDefaultColor(
                         this, com.android.internal.R.attr.colorAccentPrimary));
+        mKeyguardFaceAuthInteractor.onWalletLaunched();
         mKeyguardViewManager.requestFace(true);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
index 8990583..167e341 100644
--- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
+++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
@@ -18,61 +18,94 @@
 import android.app.ActivityManager
 import android.app.admin.DevicePolicyManager
 import android.os.UserManager
+import android.util.DisplayMetrics
+import com.android.internal.logging.MetricsLogger
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.GuestResumeSessionReceiver
 import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.ScreenLifecycle
+import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.dagger.BroadcastDispatcherLog
 import com.android.systemui.log.dagger.SceneFrameworkLog
+import com.android.systemui.media.controls.ui.MediaHierarchyManager
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.DarkIconDispatcher
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.NotificationShadeDepthController
+import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.stack.AmbientState
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.phone.ScrimController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.SplitShadeStateController
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.util.mockito.mock
 import com.android.wm.shell.bubbles.Bubbles
+import dagger.Binds
 import dagger.Module
 import dagger.Provides
 import java.util.Optional
 
-@Module
+@Module(includes = [TestMocksModule.Bindings::class])
 data class TestMocksModule(
     @get:Provides val activityStarter: ActivityStarter = mock(),
+    @get:Provides val ambientState: AmbientState = mock(),
     @get:Provides val bubbles: Optional<Bubbles> = Optional.of(mock()),
-    @get:Provides val configurationController: ConfigurationController = mock(),
     @get:Provides val darkIconDispatcher: DarkIconDispatcher = mock(),
     @get:Provides val demoModeController: DemoModeController = mock(),
     @get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),
     @get:Provides val dozeParameters: DozeParameters = mock(),
+    @get:Provides val dumpManager: DumpManager = mock(),
     @get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(),
     @get:Provides val keyguardBypassController: KeyguardBypassController = mock(),
     @get:Provides val keyguardSecurityModel: KeyguardSecurityModel = mock(),
     @get:Provides val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(),
-    @get:Provides val notifListener: NotificationListener = mock(),
-    @get:Provides val notifMediaManager: NotificationMediaManager = mock(),
-    @get:Provides val screenOffAnimController: ScreenOffAnimationController = mock(),
-    @get:Provides val splitShadeStateController: SplitShadeStateController = mock(),
-    @get:Provides val statusBarStateController: StatusBarStateController = mock(),
+    @get:Provides val mediaHierarchyManager: MediaHierarchyManager = mock(),
+    @get:Provides val notificationListener: NotificationListener = mock(),
+    @get:Provides val notificationLockscreenUserManager: NotificationLockscreenUserManager = mock(),
+    @get:Provides val notificationMediaManager: NotificationMediaManager = mock(),
+    @get:Provides val notificationShadeDepthController: NotificationShadeDepthController = mock(),
+    @get:Provides
+    val notificationStackScrollLayoutController: NotificationStackScrollLayoutController = mock(),
+    @get:Provides val notificationStackSizeCalculator: NotificationStackSizeCalculator = mock(),
+    @get:Provides val notificationWakeUpCoordinator: NotificationWakeUpCoordinator = mock(),
+    @get:Provides val screenLifecycle: ScreenLifecycle = mock(),
+    @get:Provides val screenOffAnimationController: ScreenOffAnimationController = mock(),
+    @get:Provides val scrimController: ScrimController = mock(),
+    @get:Provides val statusBarStateController: SysuiStatusBarStateController = mock(),
     @get:Provides val statusBarWindowController: StatusBarWindowController = mock(),
-    @get:Provides val wakeUpCoordinator: NotificationWakeUpCoordinator = mock(),
+    @get:Provides val wakefulnessLifecycle: WakefulnessLifecycle = mock(),
 
     // log buffers
     @get:[Provides BroadcastDispatcherLog]
     val broadcastDispatcherLogger: LogBuffer = mock(),
     @get:[Provides SceneFrameworkLog]
     val sceneLogger: LogBuffer = mock(),
+    @get:Provides val lsShadeTransitionLogger: LSShadeTransitionLogger = mock(),
 
     // framework mocks
     @get:Provides val activityManager: ActivityManager = mock(),
     @get:Provides val devicePolicyManager: DevicePolicyManager = mock(),
+    @get:Provides val displayMetrics: DisplayMetrics = mock(),
+    @get:Provides val metricsLogger: MetricsLogger = mock(),
     @get:Provides val userManager: UserManager = mock(),
-)
+) {
+    @Module
+    interface Bindings {
+        @Binds
+        fun bindStatusBarStateController(
+            sysuiStatusBarStateController: SysuiStatusBarStateController,
+        ): StatusBarStateController
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index f943acd..d8a2c5f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -25,7 +25,6 @@
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -47,7 +46,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPasswordViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index e090093..dc1618d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -25,7 +25,6 @@
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
@@ -53,7 +52,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPatternViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 8322b37..4a24e4a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -31,14 +31,13 @@
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.SingleTapClassifier;
 import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.res.R;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -47,7 +46,6 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 2f08804..9df4dd4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -26,7 +26,6 @@
 import com.android.internal.widget.LockPatternUtils
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
@@ -53,7 +52,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPinViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
index f3a1b68..5102957 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
@@ -69,7 +69,8 @@
         when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
         when(mMockKeyguardStatusView.getContext()).thenReturn(mContext);
         when(mMockKeyguardStatusView.findViewById(R.id.clock)).thenReturn(mMockKeyguardStatusView);
-        when(mKeyguardStatusViewComponentFactory.build(any(KeyguardStatusView.class)))
+        when(mKeyguardStatusViewComponentFactory.build(any(KeyguardStatusView.class),
+                any(Display.class)))
                 .thenReturn(mKeyguardStatusViewComponent);
         when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
                 .thenReturn(mKeyguardClockSwitchController);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index d54843d3..20d4eb9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -36,7 +36,6 @@
 import com.android.internal.widget.LockPatternUtils
 import com.android.keyguard.KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate
 import com.android.systemui.biometrics.SideFpsController
@@ -100,7 +99,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index aad11d9..156e068 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -56,11 +56,10 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingA11yDelegate;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.user.data.source.UserRecord;
 import com.android.systemui.util.settings.GlobalSettings;
@@ -76,7 +75,6 @@
 import java.util.ArrayList;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityContainerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
index b02b1f9..7bb6ef1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
@@ -35,10 +35,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.res.R;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -50,7 +49,6 @@
 import org.mockito.junit.MockitoRule;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index d0bb5a9..4290b8b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -25,7 +25,6 @@
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -44,7 +43,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardSimPinViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
index 59cd26c..31ee641 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
@@ -25,7 +25,6 @@
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -40,7 +39,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardSimPukViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
index 989164e..3b8e02f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
@@ -20,7 +20,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.animation.LayoutTransition;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
@@ -69,7 +68,6 @@
 
     @Mock protected KeyguardClockSwitch mKeyguardClockSwitch;
     @Mock protected FrameLayout mMediaHostContainer;
-    @Mock protected LayoutTransition mMediaLayoutTransition;
 
     @Before
     public void setup() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index e4e2b0a..948942f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -16,22 +16,27 @@
 
 package com.android.keyguard;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.animation.LayoutTransition;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
 
-import com.android.systemui.res.R;
+import com.android.app.animation.Interpolators;
+import com.android.systemui.animation.ViewHierarchyAnimator;
 import com.android.systemui.plugins.ClockConfig;
 import com.android.systemui.plugins.ClockController;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
@@ -39,6 +44,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
+import java.lang.reflect.Field;
+
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @RunWith(AndroidTestingRunner.class)
@@ -81,7 +88,7 @@
     public void updatePosition_primaryClockAnimation() {
         ClockController mockClock = mock(ClockController.class);
         when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
-        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", false, true));
+        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", "", "", false, true));
 
         mController.updatePosition(10, 15, 20f, true);
 
@@ -96,7 +103,7 @@
     public void updatePosition_alternateClockAnimation() {
         ClockController mockClock = mock(ClockController.class);
         when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
-        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", true, true));
+        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", "", "", true, true));
 
         mController.updatePosition(10, 15, 20f, true);
 
@@ -142,19 +149,7 @@
     }
 
     @Test
-    public void onInit_addsOnLayoutChangeListenerToMediaHostContainer() {
-        when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
-                mMediaHostContainer);
-
-        mController.onInit();
-
-        ArgumentCaptor<View.OnLayoutChangeListener> captor =
-                ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
-        verify(mMediaHostContainer).addOnLayoutChangeListener(captor.capture());
-    }
-
-    @Test
-    public void clockSwitchHeightChanged_mediaChangingLayoutTransitionEnabled() {
+    public void clockSwitchHeightChanged_animatesMediaHostContainer() {
         when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
                 mMediaHostContainer);
 
@@ -167,6 +162,10 @@
         // Above here is the same as `onInit_addsOnLayoutChangeListenerToClockSwitch`.
         // Below here is the actual test.
 
+        ViewHierarchyAnimator.Companion animator = ViewHierarchyAnimator.Companion;
+        ViewHierarchyAnimator.Companion spiedAnimator = spy(animator);
+        setCompanion(spiedAnimator);
+
         View.OnLayoutChangeListener listener = captor.getValue();
 
         mController.setSplitShadeEnabled(true);
@@ -174,17 +173,20 @@
         when(mKeyguardUpdateMonitor.isKeyguardVisible()).thenReturn(true);
         when(mMediaHostContainer.getVisibility()).thenReturn(View.VISIBLE);
         when(mMediaHostContainer.getHeight()).thenReturn(200);
-        when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition);
 
         when(mKeyguardClockSwitch.getHeight()).thenReturn(0);
         listener.onLayoutChange(mKeyguardClockSwitch, /* left= */ 0, /* top= */ 0, /* right= */
                 0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */
                 0, /* oldBottom = */ 200);
-        verify(mMediaLayoutTransition).enableTransitionType(LayoutTransition.CHANGING);
+        verify(spiedAnimator).animateNextUpdate(mMediaHostContainer,
+                Interpolators.STANDARD, /* duration= */ 500L, /* animateChildren= */ false);
+
+        // Resets ViewHierarchyAnimator.Companion to its original value
+        setCompanion(animator);
     }
 
     @Test
-    public void clockSwitchHeightNotChanged_mediaChangingLayoutTransitionNotEnabled() {
+    public void clockSwitchHeightNotChanged_doesNotAnimateMediaOutputContainer() {
         when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
                 mMediaHostContainer);
 
@@ -197,6 +199,10 @@
         // Above here is the same as `onInit_addsOnLayoutChangeListenerToClockSwitch`.
         // Below here is the actual test.
 
+        ViewHierarchyAnimator.Companion animator = ViewHierarchyAnimator.Companion;
+        ViewHierarchyAnimator.Companion spiedAnimator = spy(animator);
+        setCompanion(spiedAnimator);
+
         View.OnLayoutChangeListener listener = captor.getValue();
 
         mController.setSplitShadeEnabled(true);
@@ -204,36 +210,24 @@
         when(mKeyguardUpdateMonitor.isKeyguardVisible()).thenReturn(true);
         when(mMediaHostContainer.getVisibility()).thenReturn(View.VISIBLE);
         when(mMediaHostContainer.getHeight()).thenReturn(200);
-        when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition);
 
         when(mKeyguardClockSwitch.getHeight()).thenReturn(200);
         listener.onLayoutChange(mKeyguardClockSwitch, /* left= */ 0, /* top= */ 0, /* right= */
                 0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */
                 0, /* oldBottom = */ 200);
-        verify(mMediaLayoutTransition, never()).enableTransitionType(LayoutTransition.CHANGING);
+        verify(spiedAnimator, never()).animateNextUpdate(any(), any(), anyLong(), anyBoolean());
+
+        // Resets ViewHierarchyAnimator.Companion to its original value
+        setCompanion(animator);
     }
 
-    @Test
-    public void onMediaHostContainerLayout_disablesChangingLayoutTransition() {
-        when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
-                mMediaHostContainer);
-
-        mController.onInit();
-
-        ArgumentCaptor<View.OnLayoutChangeListener> captor =
-                ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
-        verify(mMediaHostContainer).addOnLayoutChangeListener(captor.capture());
-
-        // Above here is the same as `onInit_addsOnLayoutChangeListenerToMediaHostContainer`.
-        // Below here is the actual test.
-
-        View.OnLayoutChangeListener listener = captor.getValue();
-
-        when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition);
-
-        when(mMediaLayoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGING)).thenReturn(
-                true);
-        listener.onLayoutChange(mMediaHostContainer, 1, 2, 3, 4, 1, 2, 3, 4);
-        verify(mMediaLayoutTransition).disableTransitionType(LayoutTransition.CHANGING);
+    private void setCompanion(ViewHierarchyAnimator.Companion companion) {
+        try {
+            Field field = ViewHierarchyAnimator.class.getDeclaredField("Companion");
+            field.setAccessible(true);
+            field.set(null, companion);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
index 58d372c..86439e5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -1,6 +1,5 @@
 package com.android.keyguard
 
-import android.animation.LayoutTransition
 import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
@@ -36,20 +35,6 @@
     }
 
     @Test
-    fun mediaViewHasLayoutTransitionInDisabledState() {
-        val layoutTransition = (mediaView as ViewGroup).layoutTransition
-        assertThat(layoutTransition).isNotNull()
-        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGE_APPEARING))
-            .isFalse()
-        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGE_DISAPPEARING))
-            .isFalse()
-        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.APPEARING)).isFalse()
-        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.DISAPPEARING))
-            .isFalse()
-        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGING)).isFalse()
-    }
-
-    @Test
     fun setChildrenTranslationYExcludingMediaView_mediaViewIsNotTranslated() {
         val translationY = 1234f
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 21a2822..d61ca69 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -39,10 +39,10 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.doze.util.BurnInHelperKt;
 import com.android.systemui.dump.DumpManager;
@@ -51,6 +51,8 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
+import com.android.systemui.scene.SceneTestUtils;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -75,6 +77,8 @@
 
     protected MockitoSession mStaticMockSession;
 
+    protected final SceneTestUtils mSceneTestUtils = new SceneTestUtils(this);
+    protected @Mock BouncerInteractor mBouncerInteractor;
     protected @Mock LockIconView mLockIconView;
     protected @Mock AnimatedStateListDrawable mIconDrawable;
     protected @Mock Context mContext;
@@ -93,6 +97,7 @@
     protected @Mock AuthRippleController mAuthRippleController;
     protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
     protected FakeFeatureFlags mFeatureFlags;
+
     protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
 
     protected LockIconViewController mUnderTest;
@@ -148,6 +153,7 @@
         mFeatureFlags.set(MIGRATE_LOCK_ICON, false);
         mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
         mFeatureFlags.set(LOCKSCREEN_ENABLE_LANDSCAPE, false);
+
         mUnderTest = new LockIconViewController(
                 mStatusBarStateController,
                 mKeyguardUpdateMonitor,
@@ -168,7 +174,9 @@
                 KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
                 mFeatureFlags,
                 mPrimaryBouncerInteractor,
-                mContext
+                mContext,
+                () -> mBouncerInteractor,
+                mSceneTestUtils.getSceneContainerFlags()
         );
     }
 
@@ -227,8 +235,8 @@
         setupLockIconViewMocks();
     }
 
-    protected void init(boolean useMigrationFlag) {
-        mFeatureFlags.set(DOZING_MIGRATION_1, useMigrationFlag);
+    protected void init(boolean useDozeMigrationFlag) {
+        mFeatureFlags.set(DOZING_MIGRATION_1, useDozeMigrationFlag);
         mUnderTest.setLockIconView(mLockIconView);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index a2dc776..4bacc3d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -17,13 +17,16 @@
 package com.android.keyguard;
 
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+
 import static com.android.keyguard.LockIconView.ICON_LOCK;
 import static com.android.keyguard.LockIconView.ICON_UNLOCK;
 import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -41,6 +44,7 @@
 import com.android.systemui.biometrics.UdfpsController;
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
 import com.android.systemui.doze.util.BurnInHelperKt;
+import com.android.systemui.statusbar.StatusBarState;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -180,13 +184,14 @@
     }
 
     @Test
-    public void testLockIcon_clearsIconOnAod_whenUdfpsNotEnrolled() {
+    public void testLockIcon_clearsIconWhenUnlocked() {
         // GIVEN udfps not enrolled
         setupUdfps();
         when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(false);
 
         // GIVEN starting state for the lock icon
         setupShowLockIcon();
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
 
         // GIVEN lock icon controller is initialized and view is attached
         init(/* useMigrationFlag= */false);
@@ -194,7 +199,7 @@
         reset(mLockIconView);
 
         // WHEN the dozing state changes
-        mStatusBarStateListener.onDozingChanged(true /* isDozing */);
+        mStatusBarStateListener.onDozingChanged(false /* isDozing */);
 
         // THEN the icon is cleared
         verify(mLockIconView).clearIcon();
@@ -400,6 +405,49 @@
 
         // THEN uses perform haptic feedback
         verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
+    }
 
+    @Test
+    public void longPress_showBouncer_sceneContainerNotEnabled() {
+        init(/* useMigrationFlag= */ false);
+        mSceneTestUtils.getSceneContainerFlags().setEnabled(false);
+        mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true);
+        when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(false);
+
+        // WHEN longPress
+        mUnderTest.onLongPress();
+
+        // THEN show primary bouncer via keyguard view controller, not scene container
+        verify(mKeyguardViewController).showPrimaryBouncer(anyBoolean());
+        verify(mBouncerInteractor, never()).showOrUnlockDevice(any());
+    }
+
+    @Test
+    public void longPress_showBouncer() {
+        init(/* useMigrationFlag= */ false);
+        mSceneTestUtils.getSceneContainerFlags().setEnabled(true);
+        mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true);
+        when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(false);
+
+        // WHEN longPress
+        mUnderTest.onLongPress();
+
+        // THEN show primary bouncer
+        verify(mKeyguardViewController, never()).showPrimaryBouncer(anyBoolean());
+        verify(mBouncerInteractor).showOrUnlockDevice(any());
+    }
+
+    @Test
+    public void longPress_falsingTriggered_doesNotShowBouncer() {
+        init(/* useMigrationFlag= */ false);
+        mSceneTestUtils.getSceneContainerFlags().setEnabled(true);
+        mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true);
+        when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(true);
+
+        // WHEN longPress
+        mUnderTest.onLongPress();
+
+        // THEN don't show primary bouncer
+        verify(mBouncerInteractor, never()).showOrUnlockDevice(any());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
index c372f45..1213518 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
 import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
 import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.util.mockito.whenever
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
@@ -42,7 +43,7 @@
 
     /** After migration, replaces LockIconViewControllerTest version */
     @Test
-    fun testLockIcon_clearsIconOnAod_whenUdfpsNotEnrolled() =
+    fun testLockIcon_clearsIconWhenUnlocked() =
         runBlocking(IMMEDIATE) {
             // GIVEN udfps not enrolled
             setupUdfps()
@@ -50,14 +51,14 @@
 
             // GIVEN starting state for the lock icon
             setupShowLockIcon()
+            whenever(mStatusBarStateController.state).thenReturn(StatusBarState.SHADE)
 
             // GIVEN lock icon controller is initialized and view is attached
             init(/* useMigrationFlag= */ true)
             reset(mLockIconView)
 
             // WHEN the dozing state changes
-            mUnderTest.mIsDozingCallback.accept(true)
-
+            mUnderTest.mIsDozingCallback.accept(false)
             // THEN the icon is cleared
             verify(mLockIconView).clearIcon()
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 59c7e76..8faf715 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -166,6 +166,9 @@
         waitForIdleSync()
         verify(controller).onLaunchAnimationCancelled()
         verify(controller, never()).onLaunchAnimationStart(anyBoolean())
+        verify(listener).onLaunchAnimationCancelled()
+        verify(listener, never()).onLaunchAnimationStart()
+        assertNull(runner.delegate)
     }
 
     @Test
@@ -176,6 +179,9 @@
         waitForIdleSync()
         verify(controller).onLaunchAnimationCancelled()
         verify(controller, never()).onLaunchAnimationStart(anyBoolean())
+        verify(listener).onLaunchAnimationCancelled()
+        verify(listener, never()).onLaunchAnimationStart()
+        assertNull(runner.delegate)
     }
 
     @Test
@@ -194,6 +200,15 @@
         }
     }
 
+    @Test
+    fun disposeRunner_delegateDereferenced() {
+        val runner = activityLaunchAnimator.createRunner(controller)
+        assertNotNull(runner.delegate)
+        runner.dispose()
+        waitForIdleSync()
+        assertNull(runner.delegate)
+    }
+
     private fun fakeWindow(): RemoteAnimationTarget {
         val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
         val taskInfo = ActivityManager.RunningTaskInfo()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt
index a7e7dd0..2b51ac5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt
@@ -19,6 +19,7 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import androidx.core.animation.doOnEnd
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.doOnEnd
@@ -30,6 +31,7 @@
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
 @RunWithLooper
+@FlakyTest(bugId = 302149604)
 class AnimatorTestRuleOrderTest : SysuiTestCase() {
 
     @get:Rule val animatorTestRule = AnimatorTestRule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index 212dad7..c2e6db3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -242,6 +242,40 @@
     }
 
     @Test
+    fun animatesRootOnly() {
+        setUpRootWithChildren()
+
+        val success = ViewHierarchyAnimator.animate(
+                rootView,
+                animateChildren = false
+        )
+        // Change all bounds.
+        rootView.measure(
+                View.MeasureSpec.makeMeasureSpec(180, View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+        )
+        rootView.layout(10 /* l */, 20 /* t */, 200 /* r */, 120 /* b */)
+
+        assertTrue(success)
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator))
+        assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator))
+        // The initial values for the root view should be those of the previous layout, while the
+        // children views should be at the final values from the beginning.
+        checkBounds(rootView, l = 0, t = 0, r = 200, b = 100)
+        checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100)
+        checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100)
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator))
+        assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator))
+        // The end values should be those of the latest layout.
+        checkBounds(rootView, l = 10, t = 20, r = 200, b = 120)
+        checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100)
+        checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100)
+    }
+
+    @Test
     fun animatesInvisibleViews() {
         rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
         rootView.visibility = View.INVISIBLE
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
index 0283382..6ac84bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
@@ -21,6 +21,7 @@
 import android.app.admin.DevicePolicyManager
 import android.content.Intent
 import android.content.pm.UserInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.keyguard.KeyguardSecurityModel
@@ -40,13 +41,12 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class AuthenticationRepositoryTest : SysuiTestCase() {
 
     @Mock private lateinit var lockPatternUtils: LockPatternUtils
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index a102890..2f5f460 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.authentication.domain.interactor
 
 import android.app.admin.DevicePolicyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
@@ -35,11 +36,10 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class AuthenticationInteractorTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 2bc0171..885abcb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -17,12 +17,15 @@
 package com.android.systemui.biometrics;
 
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+
 import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotSame;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -79,7 +82,6 @@
 import com.android.internal.R;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
 import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
@@ -114,7 +116,6 @@
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper
 @SmallTest
-@RoboPilotTest
 public class AuthControllerTest extends SysuiTestCase {
 
     private static final long REQUEST_ID = 22;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index 7365460..d68a313 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -16,36 +16,18 @@
 
 package com.android.systemui.biometrics
 
-import android.app.ActivityManager
-import android.os.UserManager
 import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
-import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.SysUITestModule
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
-import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
-import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.interactor.GuestUserInteractor
-import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
-import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
-import com.android.systemui.user.domain.interactor.UserInteractor
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.user.domain.UserDomainLayerModule
+import dagger.BindsInstance
+import dagger.Component
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -58,91 +40,27 @@
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
 class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
-    private val utils = SceneTestUtils(this)
-    private val testScope = utils.testScope
-    private val testDispatcher = utils.testDispatcher
-    private val disableFlagsRepository = FakeDisableFlagsRepository()
-    private val featureFlags = FakeFeatureFlags()
-    private val keyguardRepository = FakeKeyguardRepository()
-    private val shadeRepository = FakeShadeRepository()
-    private val sceneContainerFlags = FakeSceneContainerFlags()
-    private val sceneInteractor = utils.sceneInteractor()
-    private val userSetupRepository = FakeUserSetupRepository()
-    private val userRepository = FakeUserRepository()
-    private val configurationRepository = FakeConfigurationRepository()
-    private val sharedNotificationContainerInteractor =
-        SharedNotificationContainerInteractor(
-            configurationRepository,
-            mContext,
-            ResourcesSplitShadeStateController()
-        )
 
-    private lateinit var detector: AuthDialogPanelInteractionDetector
-    private lateinit var shadeInteractor: ShadeInteractor
-    private lateinit var userInteractor: UserInteractor
+    private val testComponent: TestComponent =
+        DaggerAuthDialogPanelInteractionDetectorTest_TestComponent.factory()
+            .create(
+                test = this,
+                featureFlags =
+                    FakeFeatureFlagsClassicModule {
+                        set(Flags.FACE_AUTH_REFACTOR, false)
+                        set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+                    },
+            )
 
     @Mock private lateinit var action: Runnable
-    @Mock private lateinit var activityManager: ActivityManager
-    @Mock private lateinit var activityStarter: ActivityStarter
-    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
-    @Mock private lateinit var guestInteractor: GuestUserInteractor
-    @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
-    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
-    @Mock private lateinit var manager: UserManager
-    @Mock private lateinit var uiEventLogger: UiEventLogger
+
+    private val testScope = testComponent.testScope
+    private val shadeRepository = testComponent.shadeRepository
+    private val detector = testComponent.detector
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-
-        featureFlags.set(Flags.FACE_AUTH_REFACTOR, false)
-        featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
-
-        val refreshUsersScheduler =
-            RefreshUsersScheduler(
-                applicationScope = testScope.backgroundScope,
-                mainDispatcher = testDispatcher,
-                repository = userRepository,
-            )
-        userInteractor =
-            UserInteractor(
-                applicationContext = context,
-                repository = userRepository,
-                activityStarter = activityStarter,
-                keyguardInteractor =
-                    KeyguardInteractorFactory.create(featureFlags = featureFlags)
-                        .keyguardInteractor,
-                featureFlags = featureFlags,
-                manager = manager,
-                headlessSystemUserMode = headlessSystemUserMode,
-                applicationScope = testScope.backgroundScope,
-                telephonyInteractor =
-                    TelephonyInteractor(
-                        repository = FakeTelephonyRepository(),
-                    ),
-                broadcastDispatcher = fakeBroadcastDispatcher,
-                keyguardUpdateMonitor = keyguardUpdateMonitor,
-                backgroundDispatcher = testDispatcher,
-                activityManager = activityManager,
-                refreshUsersScheduler = refreshUsersScheduler,
-                guestUserInteractor = guestInteractor,
-                uiEventLogger = uiEventLogger,
-                userRestrictionChecker = mock(),
-            )
-        shadeInteractor =
-            ShadeInteractor(
-                testScope.backgroundScope,
-                disableFlagsRepository,
-                sceneContainerFlags,
-                { sceneInteractor },
-                keyguardRepository,
-                userSetupRepository,
-                deviceProvisionedController,
-                userInteractor,
-                sharedNotificationContainerInteractor,
-                shadeRepository,
-            )
-        detector = AuthDialogPanelInteractionDetector(testScope, { shadeInteractor })
     }
 
     @Test
@@ -215,4 +133,27 @@
             // Clean up job
             detector.disable()
         }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val detector: AuthDialogPanelInteractionDetector
+        val shadeRepository: FakeShadeRepository
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
index 8547fa3..714461b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
@@ -38,7 +38,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 
 import kotlin.Unit;
@@ -53,7 +52,6 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class BiometricDisplayListenerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
index ab5d8bea5..39f0d57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
@@ -19,7 +19,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.logging.BiometricMessageDeferralLogger
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import org.junit.Assert.assertEquals
@@ -34,7 +33,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class FaceHelpMessageDeferralTest : SysuiTestCase() {
     val threshold = .75f
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index 57cf834..ef06e0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -53,7 +53,6 @@
 import com.airbnb.lottie.LottieAnimationView
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.SysuiTestableContext
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
@@ -98,7 +97,6 @@
 private const val REAR_DISPLAY_MODE_DEVICE_STATE = 3
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class SideFpsControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
index 469f65a..e2aa984 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt
@@ -19,7 +19,6 @@
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dump.DumpManager
@@ -35,7 +34,6 @@
 import org.mockito.junit.MockitoJUnit
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class UdfpsBpViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 21e614f..ebe13fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -29,7 +29,6 @@
 import android.view.LayoutInflater
 import android.view.MotionEvent
 import android.view.Surface
-import android.view.Surface.ROTATION_0
 import android.view.Surface.Rotation
 import android.view.View
 import android.view.WindowManager
@@ -38,7 +37,6 @@
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
@@ -46,7 +44,6 @@
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -83,7 +80,6 @@
 
 @ExperimentalCoroutinesApi
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 class UdfpsControllerOverlayTest : SysuiTestCase() {
@@ -143,7 +139,6 @@
     ) {
         controllerOverlay = UdfpsControllerOverlay(
             context,
-            fingerprintManager,
             inflater,
             windowManager,
             accessibilityManager,
@@ -157,7 +152,6 @@
             keyguardStateController,
             unlockedScreenOffAnimationController,
             udfpsDisplayMode,
-            secureSettings,
             REQUEST_ID,
             reason,
             controllerCallback,
@@ -167,7 +161,6 @@
             primaryBouncerInteractor,
             alternateBouncerInteractor,
             isDebuggable,
-            udfpsUtils,
             udfpsKeyguardAccessibilityDelegate,
             udfpsKeyguardViewModels,
         )
@@ -214,8 +207,8 @@
             val lp = layoutParamsCaptor.value
             assertThat(lp.x).isEqualTo(0)
             assertThat(lp.y).isEqualTo(0)
-            assertThat(lp.width).isEqualTo(SENSOR_WIDTH)
-            assertThat(lp.height).isEqualTo(SENSOR_HEIGHT)
+            assertThat(lp.width).isEqualTo(DISPLAY_WIDTH)
+            assertThat(lp.height).isEqualTo(DISPLAY_HEIGHT)
         }
     }
 
@@ -232,8 +225,8 @@
             val lp = layoutParamsCaptor.value
             assertThat(lp.x).isEqualTo(0)
             assertThat(lp.y).isEqualTo(0)
-            assertThat(lp.width).isEqualTo(SENSOR_WIDTH)
-            assertThat(lp.height).isEqualTo(SENSOR_HEIGHT)
+            assertThat(lp.width).isEqualTo(DISPLAY_WIDTH)
+            assertThat(lp.height).isEqualTo(DISPLAY_HEIGHT)
         }
     }
 
@@ -249,9 +242,9 @@
             // Sensor should be in the bottom left corner in ROTATION_90.
             val lp = layoutParamsCaptor.value
             assertThat(lp.x).isEqualTo(0)
-            assertThat(lp.y).isEqualTo(DISPLAY_WIDTH - SENSOR_WIDTH)
-            assertThat(lp.width).isEqualTo(SENSOR_HEIGHT)
-            assertThat(lp.height).isEqualTo(SENSOR_WIDTH)
+            assertThat(lp.y).isEqualTo(0)
+            assertThat(lp.width).isEqualTo(DISPLAY_HEIGHT)
+            assertThat(lp.height).isEqualTo(DISPLAY_WIDTH)
         }
     }
 
@@ -266,10 +259,10 @@
 
             // Sensor should be in the top right corner in ROTATION_270.
             val lp = layoutParamsCaptor.value
-            assertThat(lp.x).isEqualTo(DISPLAY_HEIGHT - SENSOR_HEIGHT)
+            assertThat(lp.x).isEqualTo(0)
             assertThat(lp.y).isEqualTo(0)
-            assertThat(lp.width).isEqualTo(SENSOR_HEIGHT)
-            assertThat(lp.height).isEqualTo(SENSOR_WIDTH)
+            assertThat(lp.width).isEqualTo(DISPLAY_HEIGHT)
+            assertThat(lp.height).isEqualTo(DISPLAY_WIDTH)
         }
     }
 
@@ -347,11 +340,10 @@
     }
 
     @Test
-    fun smallOverlayOnEnrollmentWithA11y() = withRotation(ROTATION_0) {
+    fun smallOverlayOnEnrollmentWithA11y() = withRotation(Surface.ROTATION_0) {
         withReason(REASON_ENROLL_ENROLLING) {
             // When a11y enabled during enrollment
             whenever(accessibilityManager.isTouchExplorationEnabled).thenReturn(true)
-            whenever(featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true)
 
             controllerOverlay.show(udfpsController, overlayParams)
             verify(windowManager).addView(
@@ -365,22 +357,4 @@
             assertThat(lp.height).isEqualTo(overlayParams.sensorBounds.height())
         }
     }
-
-    @Test
-    fun fullScreenOverlayWithNewTouchDetectionEnabled() = withRotation(ROTATION_0) {
-        withReason(REASON_AUTH_KEYGUARD) {
-            whenever(featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true)
-
-            controllerOverlay.show(udfpsController, overlayParams)
-            verify(windowManager).addView(
-                    eq(controllerOverlay.overlayView),
-                    layoutParamsCaptor.capture()
-            )
-
-            // Layout params should use natural display width and height
-            val lp = layoutParamsCaptor.value
-            assertThat(lp.width).isEqualTo(overlayParams.naturalDisplayWidth)
-            assertThat(lp.height).isEqualTo(overlayParams.naturalDisplayHeight)
-        }
-    }
 }
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 ee3bd0d..dcb5398 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -20,12 +20,15 @@
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_UP;
+
 import static com.android.internal.util.FunctionalUtils.ThrowingConsumer;
 import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
 import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -74,8 +77,6 @@
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
@@ -87,13 +88,13 @@
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -103,7 +104,6 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecution;
 import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.util.time.SystemClock;
 
@@ -120,12 +120,10 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Optional;
 
 import javax.inject.Provider;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class UdfpsControllerTest extends SysuiTestCase {
@@ -205,8 +203,6 @@
     @Mock
     private ActivityLaunchAnimator mActivityLaunchAnimator;
     @Mock
-    private AlternateUdfpsTouchProvider mAlternateTouchProvider;
-    @Mock
     private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     @Mock
     private SinglePointerTouchProcessor mSinglePointerTouchProcessor;
@@ -215,8 +211,6 @@
     @Mock
     private AlternateBouncerInteractor mAlternateBouncerInteractor;
     @Mock
-    private SecureSettings mSecureSettings;
-    @Mock
     private UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
     @Mock
     private Provider<UdfpsKeyguardViewModels> mUdfpsKeyguardViewModels;
@@ -238,7 +232,6 @@
     private ScreenLifecycle.Observer mScreenObserver;
     private FingerprintSensorPropertiesInternal mOpticalProps;
     private FingerprintSensorPropertiesInternal mUltrasonicProps;
-    private UdfpsUtils mUdfpsUtils;
     @Mock
     private InputManager mInputManager;
     @Mock
@@ -249,8 +242,6 @@
         mContext.getOrCreateTestableResources()
                 .addOverride(com.android.internal.R.bool.config_ignoreUdfpsVote, false);
 
-        mUdfpsUtils = new UdfpsUtils();
-
         when(mLayoutInflater.inflate(R.layout.udfps_view, null, false))
                 .thenReturn(mUdfpsView);
         when(mLayoutInflater.inflate(R.layout.udfps_keyguard_view_legacy, null))
@@ -291,24 +282,13 @@
         // Create a fake background executor.
         mBiometricExecutor = new FakeExecutor(new FakeSystemClock());
 
-        initUdfpsController(true /* hasAlternateTouchProvider */);
+        initUdfpsController(mOpticalProps);
     }
 
-
-    private void initUdfpsController(boolean hasAlternateTouchProvider) {
-        initUdfpsController(mOpticalProps, hasAlternateTouchProvider);
-    }
-
-    private void initUdfpsController(FingerprintSensorPropertiesInternal sensorProps,
-            boolean hasAlternateTouchProvider) {
+    private void initUdfpsController(FingerprintSensorPropertiesInternal sensorProps) {
         reset(mFingerprintManager);
         reset(mScreenLifecycle);
 
-        final Optional<Provider<AlternateUdfpsTouchProvider>> alternateTouchProvider =
-                hasAlternateTouchProvider ? Optional.of(
-                        (Provider<AlternateUdfpsTouchProvider>) () -> mAlternateTouchProvider)
-                        : Optional.empty();
-
         mUdfpsController = new UdfpsController(
                 mContext,
                 new FakeExecution(),
@@ -338,15 +318,12 @@
                 mSystemUIDialogManager,
                 mLatencyTracker,
                 mActivityLaunchAnimator,
-                alternateTouchProvider,
                 mBiometricExecutor,
                 mPrimaryBouncerInteractor,
                 mSinglePointerTouchProcessor,
                 mSessionTracker,
                 mAlternateBouncerInteractor,
-                mSecureSettings,
                 mInputManager,
-                mUdfpsUtils,
                 mock(KeyguardFaceAuthInteractor.class),
                 mUdfpsKeyguardAccessibilityDelegate,
                 mUdfpsKeyguardViewModels
@@ -373,17 +350,15 @@
     public void onActionDownTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
         // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
 
-        // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
 
         // WHEN ACTION_DOWN is received
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.first);
+        MotionEvent downEvent = obtainMotionEvent(ACTION_DOWN, 0, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
         mBiometricExecutor.runAllReady();
         downEvent.recycle();
@@ -407,16 +382,14 @@
             throws RemoteException {
         // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
 
-        // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
 
         // WHEN ACTION_MOVE is received
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.first);
         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
         if (stale) {
             mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId);
@@ -435,22 +408,22 @@
     public void onMultipleTouch_whenCanDismissLockScreen_entersDeviceOnce() throws RemoteException {
         // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
 
-        // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UNCHANGED, false);
 
-        // WHEN multiple touches are received
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        // GIVEN that the overlay is showing
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.first);
         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
         mBiometricExecutor.runAllReady();
         downEvent.recycle();
+
         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.second);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
         mBiometricExecutor.runAllReady();
         moveEvent.recycle();
@@ -592,22 +565,17 @@
 
     private static class TestParams {
         public final FingerprintSensorPropertiesInternal sensorProps;
-        public final boolean hasAlternateTouchProvider;
 
-        TestParams(FingerprintSensorPropertiesInternal sensorProps,
-                boolean hasAlternateTouchProvider) {
+        TestParams(FingerprintSensorPropertiesInternal sensorProps) {
             this.sensorProps = sensorProps;
-            this.hasAlternateTouchProvider = hasAlternateTouchProvider;
         }
     }
 
     private void runWithAllParams(ThrowingConsumer<TestParams> testParamsConsumer) {
         for (FingerprintSensorPropertiesInternal sensorProps : List.of(mOpticalProps,
                 mUltrasonicProps)) {
-            for (boolean hasAlternateTouchProvider : new boolean[]{false, true}) {
-                initUdfpsController(sensorProps, hasAlternateTouchProvider);
-                testParamsConsumer.accept(new TestParams(sensorProps, hasAlternateTouchProvider));
-            }
+            initUdfpsController(sensorProps);
+            testParamsConsumer.accept(new TestParams(sensorProps));
         }
     }
 
@@ -620,23 +588,33 @@
     private void onTouch_propagatesTouchInNativeOrientationAndResolutionParameterized(
             TestParams testParams) throws RemoteException {
         reset(mUdfpsView);
+        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
 
         final Rect sensorBounds = new Rect(1000, 1900, 1080, 1920); // Bottom right corner.
+        final int pointerId = 0;
         final int displayWidth = 1080;
         final int displayHeight = 1920;
-        final float scaleFactor = 0.75f; // This means the native resolution is 1440x2560.
+        final float scaleFactor = 1f; // This means the native resolution is 1440x2560.
         final float touchMinor = 10f;
         final float touchMajor = 20f;
+        final float orientation = 30f;
 
         // Expecting a touch at the very bottom right corner in native orientation and resolution.
-        final int expectedX = (int) (displayWidth / scaleFactor);
-        final int expectedY = (int) (displayHeight / scaleFactor);
+        final float expectedX = displayWidth / scaleFactor;
+        final float expectedY = displayHeight / scaleFactor;
         final float expectedMinor = touchMinor / scaleFactor;
         final float expectedMajor = touchMajor / scaleFactor;
 
         // Configure UdfpsView to accept the ACTION_DOWN event
         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+        // GIVEN a valid touch on sensor
+        NormalizedTouchData touchData = new NormalizedTouchData(pointerId, displayWidth,
+                displayHeight, touchMinor, touchMajor, orientation, 0L, 0L);
+        TouchProcessorResult processorDownResult = new TouchProcessorResult.ProcessedTouch(
+                InteractionEvent.DOWN, 1, touchData);
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                processorDownResult);
 
         // Show the overlay.
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
@@ -653,21 +631,12 @@
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
         mBiometricExecutor.runAllReady();
         event.recycle();
-        event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-        if (testParams.hasAlternateTouchProvider) {
-            verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
-                    eq(expectedY), eq(expectedMinor), eq(expectedMajor));
-        } else {
-            verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                    eq(testParams.sensorProps.sensorId), eq(expectedX), eq(expectedY),
-                    eq(expectedMinor), eq(expectedMajor));
-        }
+        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+                eq(testParams.sensorProps.sensorId), eq(pointerId), eq(expectedX), eq(expectedY),
+                eq(expectedMinor), eq(expectedMajor), eq(orientation), anyLong(), anyLong(),
+                anyBoolean());
 
         // Test ROTATION_90
-        reset(mAlternateTouchProvider);
         reset(mFingerprintManager);
         mUdfpsController.updateOverlayParams(testParams.sensorProps,
                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
@@ -676,21 +645,12 @@
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
         mBiometricExecutor.runAllReady();
         event.recycle();
-        event = obtainMotionEvent(ACTION_MOVE, displayHeight, 0, touchMinor, touchMajor);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-        if (testParams.hasAlternateTouchProvider) {
-            verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
-                    eq(expectedY), eq(expectedMinor), eq(expectedMajor));
-        } else {
-            verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                    eq(testParams.sensorProps.sensorId), eq(expectedX), eq(expectedY),
-                    eq(expectedMinor), eq(expectedMajor));
-        }
+        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+                eq(testParams.sensorProps.sensorId), eq(pointerId), eq(expectedX), eq(expectedY),
+                eq(expectedMinor), eq(expectedMajor), eq(orientation), anyLong(), anyLong(),
+                anyBoolean());
 
         // Test ROTATION_270
-        reset(mAlternateTouchProvider);
         reset(mFingerprintManager);
         mUdfpsController.updateOverlayParams(testParams.sensorProps,
                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
@@ -699,21 +659,12 @@
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
         mBiometricExecutor.runAllReady();
         event.recycle();
-        event = obtainMotionEvent(ACTION_MOVE, 0, displayWidth, touchMinor, touchMajor);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-        if (testParams.hasAlternateTouchProvider) {
-            verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
-                    eq(expectedY), eq(expectedMinor), eq(expectedMajor));
-        } else {
-            verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                    eq(testParams.sensorProps.sensorId), eq(expectedX), eq(expectedY),
-                    eq(expectedMinor), eq(expectedMajor));
-        }
+        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+                eq(testParams.sensorProps.sensorId), eq(pointerId), eq(expectedX), eq(expectedY),
+                eq(expectedMinor), eq(expectedMajor), eq(orientation), anyLong(), anyLong(),
+                anyBoolean());
 
         // Test ROTATION_180
-        reset(mAlternateTouchProvider);
         reset(mFingerprintManager);
         mUdfpsController.updateOverlayParams(testParams.sensorProps,
                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
@@ -723,18 +674,10 @@
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
         mBiometricExecutor.runAllReady();
         event.recycle();
-        event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
-        mBiometricExecutor.runAllReady();
-        event.recycle();
-        if (testParams.hasAlternateTouchProvider) {
-            verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
-                    eq(expectedY), eq(expectedMinor), eq(expectedMajor));
-        } else {
-            verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                    eq(testParams.sensorProps.sensorId), eq(expectedX), eq(expectedY),
-                    eq(expectedMinor), eq(expectedMajor));
-        }
+        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+                eq(testParams.sensorProps.sensorId), eq(pointerId), eq(expectedX), eq(expectedY),
+                eq(expectedMinor), eq(expectedMajor), eq(orientation), anyLong(), anyLong(),
+                anyBoolean());
     }
 
     @Test
@@ -743,46 +686,36 @@
     }
 
     private void fingerDownParameterized(TestParams testParams) throws RemoteException {
-        reset(mUdfpsView, mAlternateTouchProvider, mFingerprintManager, mLatencyTracker,
+        reset(mUdfpsView, mFingerprintManager, mLatencyTracker,
                 mKeyguardUpdateMonitor);
+        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
 
         // Configure UdfpsView to accept the ACTION_DOWN event
         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
 
-        // GIVEN that the overlay is showing
+        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
+                0L);
+        final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
+                InteractionEvent.DOWN, 1 /* pointerId */, touchData);
+
+        initUdfpsController(testParams.sensorProps);
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
 
         // WHEN ACTION_DOWN is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                processorResultDown);
         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
         mBiometricExecutor.runAllReady();
         downEvent.recycle();
 
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
-
-        mFgExecutor.runAllReady();
-
         // THEN the touch provider is notified about onPointerDown.
-        if (testParams.hasAlternateTouchProvider) {
-            verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0), eq(0f),
-                    eq(0f));
-            verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
-                    anyInt(), anyFloat(), anyFloat());
-            verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID));
-        } else {
-            verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                    eq(testParams.sensorProps.sensorId), eq(0), eq(0), eq(0f), eq(0f));
-            verify(mAlternateTouchProvider, never()).onPointerDown(anyInt(), anyInt(), anyInt(),
-                    anyFloat(), anyFloat());
-        }
+        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
+                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
 
         // AND display configuration begins
         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
@@ -799,33 +732,20 @@
             // AND onDisplayConfigured notifies FingerprintManager about onUiReady
             mOnDisplayConfiguredCaptor.getValue().run();
             mBiometricExecutor.runAllReady();
-            if (testParams.hasAlternateTouchProvider) {
-                InOrder inOrder = inOrder(mAlternateTouchProvider, mLatencyTracker);
-                inOrder.verify(mAlternateTouchProvider).onUiReady();
-                inOrder.verify(mLatencyTracker).onActionEnd(
-                        eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
-                verify(mFingerprintManager, never()).onUdfpsUiEvent(
-                        eq(FingerprintManager.UDFPS_UI_READY), anyLong(), anyInt());
-            } else {
-                InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
-                inOrder.verify(mFingerprintManager).onUdfpsUiEvent(
-                        eq(FingerprintManager.UDFPS_UI_READY), eq(TEST_REQUEST_ID),
-                        eq(testParams.sensorProps.sensorId));
-                inOrder.verify(mLatencyTracker).onActionEnd(
-                        eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
-                verify(mAlternateTouchProvider, never()).onUiReady();
-            }
+            InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
+            inOrder.verify(mFingerprintManager).onUdfpsUiEvent(
+                    eq(FingerprintManager.UDFPS_UI_READY), eq(TEST_REQUEST_ID),
+                    eq(testParams.sensorProps.sensorId));
+            inOrder.verify(mLatencyTracker).onActionEnd(
+                    eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
         } else {
             verify(mFingerprintManager, never()).onUdfpsUiEvent(
                     eq(FingerprintManager.UDFPS_UI_READY), anyLong(), anyInt());
-            verify(mAlternateTouchProvider, never()).onUiReady();
             verify(mLatencyTracker, never()).onActionEnd(
                     eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
         }
     }
 
-
-
     @Test
     public void aodInterrupt() {
         runWithAllParams(this::aodInterruptParameterized);
@@ -833,8 +753,9 @@
 
     private void aodInterruptParameterized(TestParams testParams) throws RemoteException {
         mUdfpsController.cancelAodSendFingerUpAction();
-        reset(mUdfpsView, mAlternateTouchProvider, mFingerprintManager, mKeyguardUpdateMonitor);
+        reset(mUdfpsView, mFingerprintManager, mKeyguardUpdateMonitor);
         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
 
         // GIVEN that the overlay is showing and screen is on and fp is running
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
@@ -854,19 +775,8 @@
         }
         mBiometricExecutor.runAllReady();
 
-        if (testParams.hasAlternateTouchProvider) {
-            verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0),
-                    eq(3f) /* minor */, eq(2f) /* major */);
-            verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
-                    anyInt(), anyFloat(), anyFloat());
-            verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID));
-        } else {
-            verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
-                    eq(testParams.sensorProps.sensorId), eq(0), eq(0), eq(3f) /* minor */,
-                    eq(2f) /* major */);
-            verify(mAlternateTouchProvider, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
-                    anyFloat(), anyFloat());
-        }
+        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
+                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
     }
 
     @Test
@@ -906,10 +816,12 @@
     private void onFingerUp_displayConfigurationParameterized(TestParams testParams)
             throws RemoteException {
         reset(mUdfpsView);
+        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
+
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
 
         // GIVEN AOD interrupt
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mScreenObserver.onScreenTurnedOn();
         mFgExecutor.runAllReady();
         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
@@ -917,7 +829,8 @@
             when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
 
             // WHEN up-action received
-            verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+            when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                    touchProcessorResult.second);
             MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
             mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
             mBiometricExecutor.runAllReady();
@@ -930,7 +843,8 @@
             when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
 
             // WHEN up-action received
-            verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+            when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                    touchProcessorResult.second);
             MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
             mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
             mBiometricExecutor.runAllReady();
@@ -1014,16 +928,19 @@
     private void aodInterruptCancelTimeoutActionOnFingerUpParameterized(TestParams testParams)
             throws RemoteException {
         reset(mUdfpsView);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
 
         // GIVEN AOD interrupt
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mScreenObserver.onScreenTurnedOn();
         mFgExecutor.runAllReady();
         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
         mFgExecutor.runAllReady();
 
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
+                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+
         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
             // Configure UdfpsView to accept the ACTION_UP event
             when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
@@ -1032,7 +949,8 @@
         }
 
         // WHEN ACTION_UP is received
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.second);
         MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
         mBiometricExecutor.runAllReady();
@@ -1042,16 +960,13 @@
         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
 
         // WHEN ACTION_DOWN is received
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.first);
         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
         mBiometricExecutor.runAllReady();
         downEvent.recycle();
 
-        // WHEN ACTION_MOVE is received
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
         mFgExecutor.runAllReady();
 
         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
@@ -1121,24 +1036,16 @@
 
     @Test
     public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled() throws RemoteException {
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
-
-        // GIVEN that the overlay is showing and a11y touch exploration enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, true);
 
         // WHEN ACTION_HOVER is received
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.first);
         verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
         MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
         mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
         enterEvent.recycle();
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
-        mHoverListenerCaptor.getValue().onHover(mUdfpsView, moveEvent);
-        moveEvent.recycle();
 
         // THEN tick haptic is played
         verify(mVibrator).vibrate(
@@ -1158,24 +1065,16 @@
     public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled_oneWayHapticsEnabled()
             throws RemoteException {
         when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
 
-        // GIVEN that the overlay is showing and a11y touch exploration enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, true);
 
         // WHEN ACTION_HOVER is received
-        verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.first);
         MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
         mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
         enterEvent.recycle();
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
-        mHoverListenerCaptor.getValue().onHover(mUdfpsView, moveEvent);
-        moveEvent.recycle();
 
         // THEN context click haptic is played
         verify(mVibrator).performHapticFeedback(
@@ -1186,26 +1085,16 @@
 
     @Test
     public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled() throws RemoteException {
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
-
-        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
 
         // WHEN ACTION_DOWN is received
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.first);
         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
         mBiometricExecutor.runAllReady();
         downEvent.recycle();
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
 
         // THEN NO haptic played
         verify(mVibrator, never()).vibrate(
@@ -1220,80 +1109,26 @@
     public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled__oneWayHapticsEnabled()
             throws RemoteException {
         when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
 
-        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
 
         // WHEN ACTION_DOWN is received
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                touchProcessorResult.first);
         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
         mBiometricExecutor.runAllReady();
         downEvent.recycle();
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
 
         // THEN NO haptic played
         verify(mVibrator, never()).performHapticFeedback(any(), anyInt());
     }
 
     @Test
-    public void onTouch_withoutNewTouchDetection_shouldCallOldFingerprintManagerPath()
-            throws RemoteException {
-        // Disable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(false);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
-
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
-
-        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-
-        // WHEN ACTION_DOWN is received
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        // AND ACTION_MOVE is received
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
-        mBiometricExecutor.runAllReady();
-        moveEvent.recycle();
-
-        // AND ACTION_UP is received
-        MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
-        mBiometricExecutor.runAllReady();
-        upEvent.recycle();
-
-        // THEN the old FingerprintManager path is invoked.
-        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(),
-                anyFloat(), anyFloat());
-        verify(mFingerprintManager).onPointerUp(anyLong(), anyInt());
-    }
-
-    @Test
     public void fingerDown_falsingManagerInformed() throws RemoteException {
         final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
-                givenAcceptFingerDownEvent();
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
 
         // WHEN ACTION_DOWN is received
         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
@@ -1307,85 +1142,46 @@
         verify(mFalsingManager).isFalseTouch(UDFPS_AUTHENTICATION);
     }
 
-    @Test
-    public void onTouch_withNewTouchDetection_shouldCallNewFingerprintManagerPath()
-            throws RemoteException {
-        final Pair<TouchProcessorResult, TouchProcessorResult> processorResultDownAndUp =
-                givenAcceptFingerDownEvent();
-
-        // WHEN ACTION_DOWN is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultDownAndUp.first);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        mBiometricExecutor.runAllReady();
-        downEvent.recycle();
-
-        // AND ACTION_UP is received
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultDownAndUp.second);
-        MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
-        mBiometricExecutor.runAllReady();
-        upEvent.recycle();
-
-        // THEN the new FingerprintManager path is invoked.
-        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
-        verify(mFingerprintManager).onPointerUp(anyLong(), anyInt(), anyInt(), anyFloat(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
-    }
-
-    private Pair<TouchProcessorResult, TouchProcessorResult> givenAcceptFingerDownEvent()
+    private Pair<TouchProcessorResult, TouchProcessorResult> givenFingerEvent(
+            InteractionEvent event1, InteractionEvent event2, boolean a11y)
             throws RemoteException {
         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
                 0L);
         final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
-                InteractionEvent.DOWN, 1 /* pointerId */, touchData);
+                event1, 1 /* pointerId */, touchData);
         final TouchProcessorResult processorResultUp = new TouchProcessorResult.ProcessedTouch(
-                InteractionEvent.UP, 1 /* pointerId */, touchData);
-
-        // Enable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
+                event2, 1 /* pointerId */, touchData);
 
         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
+        initUdfpsController(mOpticalProps);
 
         // Configure UdfpsView to accept the ACTION_DOWN event
         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
 
         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(a11y);
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        if (a11y) {
+            verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
+        } else {
+            verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        }
 
         return new Pair<>(processorResultDown, processorResultUp);
     }
 
     @Test
-    public void onTouch_WithNewTouchDetection_forwardToKeyguard() throws RemoteException {
+    public void onTouch_forwardToKeyguard() throws RemoteException {
         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
                 0L);
         final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
                 InteractionEvent.UNCHANGED, -1 /* pointerOnSensorId */, touchData);
 
-        // Enable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
-
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(false);
-
         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
@@ -1401,47 +1197,23 @@
 
         // THEN the touch is forwarded to Keyguard
         verify(mStatusBarKeyguardViewManager).onTouch(downEvent);
-        downEvent.recycle();
     }
 
     @Test
-    public void onTouch_withNewTouchDetection_pilferPointer() throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
-                InteractionEvent.DOWN, 1 /* pointerId */, touchData);
-
-        // Enable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
-
-        // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
-
-        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+    public void onTouch_pilferPointer() throws RemoteException {
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UNCHANGED, false);
 
         // WHEN ACTION_DOWN is received
         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultDown);
+                touchProcessorResult.first);
         MotionEvent event = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
         mBiometricExecutor.runAllReady();
 
         // WHEN ACTION_MOVE is received after
-        final TouchProcessorResult processorResultUnchanged =
-                new TouchProcessorResult.ProcessedTouch(
-                        InteractionEvent.UNCHANGED, 1 /* pointerId */, touchData);
         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultUnchanged);
+                touchProcessorResult.second);
         event.setAction(ACTION_MOVE);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
         mBiometricExecutor.runAllReady();
@@ -1452,25 +1224,13 @@
     }
 
     @Test
-    public void onTouch_withNewTouchDetection_doNotPilferPointer() throws RemoteException {
+    public void onTouch_doNotPilferPointer() throws RemoteException {
         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
                 0L);
         final TouchProcessorResult processorResultUnchanged =
                 new TouchProcessorResult.ProcessedTouch(InteractionEvent.UNCHANGED,
-                        1 /* pointerId */, touchData);
+                        -1 /* pointerId */, touchData);
 
-        // Enable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
-
-        // Configure UdfpsView to not accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(false);
-
-        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
@@ -1490,36 +1250,17 @@
     }
 
     @Test
-    public void onTouch_withNewTouchDetection_pilferPointerWhenAltBouncerShowing()
+    public void onTouch_pilferPointerWhenAltBouncerShowing()
             throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultUnchanged =
-                new TouchProcessorResult.ProcessedTouch(InteractionEvent.UNCHANGED,
-                        1 /* pointerId */, touchData);
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.UNCHANGED, InteractionEvent.UP, false);
 
-        // Enable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
-
-        // Configure UdfpsView to not accept the ACTION_DOWN event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(false);
-
-        // GIVEN that the alternate bouncer is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+        // WHEN alternate bouncer is showing
         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
 
         // WHEN ACTION_DOWN is received and touch is not within sensor
         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultUnchanged);
+                touchProcessorResult.first);
         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
         mBiometricExecutor.runAllReady();
@@ -1530,32 +1271,10 @@
     }
 
     @Test
-    public void onTouch_withNewTouchDetection_doNotProcessTouchWhenPullingUpBouncer()
+    public void onTouch_doNotProcessTouchWhenPullingUpBouncer()
             throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultMove =
-                new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
-                        1 /* pointerId */, touchData);
-
-        // Enable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
-
-        // Configure UdfpsView to accept the ACTION_MOVE event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
-
-        // GIVEN that the alternate bouncer is not showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
-        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.UNCHANGED, InteractionEvent.UP, false);
 
         // GIVEN a swipe up to bring up primary bouncer is in progress or swipe down for QS
         when(mPrimaryBouncerInteractor.isInTransit()).thenReturn(true);
@@ -1563,7 +1282,7 @@
 
         // WHEN ACTION_MOVE is received and touch is within sensor
         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultMove);
+                touchProcessorResult.first);
         MotionEvent moveEvent = MotionEvent.obtain(0, 0, ACTION_MOVE, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
         mBiometricExecutor.runAllReady();
@@ -1577,40 +1296,19 @@
 
 
     @Test
-    public void onTouch_withNewTouchDetection_qsDrag_processesTouchWhenAlternateBouncerVisible()
+    public void onTouch_qsDrag_processesTouchWhenAlternateBouncerVisible()
             throws RemoteException {
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultMove =
-                new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
-                        1 /* pointerId */, touchData);
+        final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+                givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
 
-        // Enable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
-
-        // Configure UdfpsView to accept the ACTION_MOVE event
-        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
-
-        // GIVEN that the alternate bouncer is showing and a11y touch exploration NOT enabled
-        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-
         // GIVEN swipe down for QS
         when(mPrimaryBouncerInteractor.isInTransit()).thenReturn(false);
         when(mLockscreenShadeTransitionController.getQSDragProgress()).thenReturn(1f);
 
         // WHEN ACTION_MOVE is received and touch is within sensor
         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultMove);
+                touchProcessorResult.first);
         MotionEvent moveEvent = MotionEvent.obtain(0, 0, ACTION_MOVE, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
         mBiometricExecutor.runAllReady();
@@ -1688,43 +1386,4 @@
         // THEN vibrate is used
         verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
     }
-
-    @Test
-    public void aodInterrupt_withNewTouchDetection() throws RemoteException {
-        mUdfpsController.cancelAodSendFingerUpAction();
-        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
-                0L);
-        final TouchProcessorResult processorResultDown =
-                new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
-                        1 /* pointerId */, touchData);
-
-        // Enable new touch detection.
-        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
-
-        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
-        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
-
-        // GIVEN that the overlay is showing and screen is on and fp is running
-        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, 0,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mScreenObserver.onScreenTurnedOn();
-        mFgExecutor.runAllReady();
-
-        // WHEN fingerprint is requested because of AOD interrupt
-        mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
-
-        // Check case where touch driver sends touch to UdfpsView as well
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
-        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
-                processorResultDown);
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-
-        mBiometricExecutor.runAllReady();
-
-        // THEN only one onPointerDown is sent
-        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
-                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
index 280bfdf..cd9189b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
@@ -27,7 +27,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Test;
@@ -38,7 +37,6 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-@RoboPilotTest
 public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
     @Test
     public void testUdfpsBottomSpacerHeightForPortrait() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
index 1afb223..5239966 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
@@ -30,7 +30,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.util.concurrency.FakeExecution;
 
@@ -41,7 +40,6 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class UdfpsDisplayModeTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
index 3276e66..e512adc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
@@ -30,7 +30,6 @@
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
@@ -116,7 +115,7 @@
     }
 
     public UdfpsKeyguardViewControllerLegacy createUdfpsKeyguardViewController() {
-        return createUdfpsKeyguardViewController(false, false);
+        return createUdfpsKeyguardViewController(false);
     }
 
     public void captureKeyGuardViewManagerCallback() {
@@ -126,8 +125,7 @@
     }
 
     protected UdfpsKeyguardViewControllerLegacy createUdfpsKeyguardViewController(
-            boolean useModernBouncer, boolean useExpandedOverlay) {
-        mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, useExpandedOverlay);
+            boolean useModernBouncer) {
         UdfpsKeyguardViewControllerLegacy controller = new UdfpsKeyguardViewControllerLegacy(
                 mView,
                 mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java
index 8508f45..21928cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java
@@ -18,27 +18,22 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.testing.TestableLooper;
-import android.view.MotionEvent;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.statusbar.StatusBarState;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4.class)
 
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -46,8 +41,7 @@
         UdfpsKeyguardViewLegacyControllerBaseTest {
     @Override
     public UdfpsKeyguardViewControllerLegacy createUdfpsKeyguardViewController() {
-        return createUdfpsKeyguardViewController(/* useModernBouncer */ false,
-                /* useExpandedOverlay */ false);
+        return createUdfpsKeyguardViewController(/* useModernBouncer */ false);
     }
 
     @Test
@@ -218,37 +212,4 @@
         sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
         assertTrue(mController.shouldPauseAuth());
     }
-
-    @Test
-    // TODO(b/259264861): Tracking Bug
-    public void testUdfpsExpandedOverlayOn() {
-        // GIVEN view is attached and useExpandedOverlay is true
-        mController = createUdfpsKeyguardViewController(false, true);
-        mController.onViewAttached();
-        captureKeyGuardViewManagerCallback();
-
-        // WHEN a touch is received
-        mKeyguardViewManagerCallback.onTouch(
-                MotionEvent.obtain(0, 0, 0, 0, 0, 0));
-
-        // THEN udfpsController onTouch is not called
-        assertTrue(mView.mUseExpandedOverlay);
-        verify(mUdfpsController, never()).onTouch(any());
-    }
-
-    @Test
-    // TODO(b/259264861): Tracking Bug
-    public void testUdfpsExpandedOverlayOff() {
-        // GIVEN view is attached and useExpandedOverlay is false
-        mController.onViewAttached();
-        captureKeyGuardViewManagerCallback();
-
-        // WHEN a touch is received
-        mKeyguardViewManagerCallback.onTouch(
-                MotionEvent.obtain(0, 0, 0, 0, 0, 0));
-
-        // THEN udfpsController onTouch is called
-        assertFalse(mView.mUseExpandedOverlay);
-        verify(mUdfpsController).onTouch(any());
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
index 17f435b..02ee53879 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -21,7 +21,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityModel
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
@@ -58,7 +57,6 @@
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
-@RoboPilotTest
 @TestableLooper.RunWithLooper
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest :
@@ -108,10 +106,7 @@
                 mock(SystemClock::class.java),
                 mKeyguardUpdateMonitor,
             )
-        return createUdfpsKeyguardViewController(
-            /* useModernBouncer */ true, /* useExpandedOverlay */
-            false
-        )
+        return createUdfpsKeyguardViewController(/* useModernBouncer */ true)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
index 6d55254..8b374ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
@@ -21,7 +21,6 @@
 import android.view.MotionEvent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.UdfpsController.UdfpsOverlayController
 import com.android.systemui.statusbar.commandline.CommandRegistry
@@ -40,7 +39,6 @@
 import org.mockito.junit.MockitoJUnit
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class UdfpsShellTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
index ebadfc7..9fbe096 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
@@ -16,8 +16,6 @@
 
 package com.android.systemui.biometrics
 
-import android.graphics.PointF
-import android.graphics.RectF
 import android.hardware.biometrics.SensorLocationInternal
 import android.testing.TestableLooper
 import android.testing.ViewUtils
@@ -26,7 +24,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
 import com.android.systemui.util.mockito.any
@@ -43,14 +40,12 @@
 import org.mockito.Mockito.nullable
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenever
 
 private const val SENSOR_X = 50
 private const val SENSOR_Y = 250
 private const val SENSOR_RADIUS = 10
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class UdfpsViewTest : SysuiTestCase() {
@@ -82,56 +77,7 @@
         ViewUtils.detachView(view)
     }
 
-    @Test
-    fun layoutSizeFitsSensor() {
-        val params = withArgCaptor<RectF> {
-            verify(animationViewController).onSensorRectUpdated(capture())
-        }
-        assertThat(params.width()).isAtLeast(2f * SENSOR_RADIUS)
-        assertThat(params.height()).isAtLeast(2f * SENSOR_RADIUS)
-    }
-
-    @Test
-    fun isWithinSensorAreaAndPaused() = isWithinSensorArea(paused = true)
-
-    @Test
-    fun isWithinSensorAreaAndNotPaused() = isWithinSensorArea(paused = false)
-
-    private fun isWithinSensorArea(paused: Boolean) {
-        whenever(animationViewController.shouldPauseAuth()).thenReturn(paused)
-        whenever(animationViewController.touchTranslation).thenReturn(PointF(0f, 0f))
-        val end = (SENSOR_RADIUS * 2) - 1
-        for (x in 1 until end) {
-            for (y in 1 until end) {
-                assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isEqualTo(!paused)
-            }
-        }
-    }
-
-    @Test
-    fun isWithinSensorAreaWhenTranslated() {
-        val offset = PointF(100f, 200f)
-        whenever(animationViewController.touchTranslation).thenReturn(offset)
-        val end = (SENSOR_RADIUS * 2) - 1
-        for (x in 0 until offset.x.toInt() step 2) {
-            for (y in 0 until offset.y.toInt() step 2) {
-                assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isFalse()
-            }
-        }
-        for (x in offset.x.toInt() + 1 until offset.x.toInt() + end) {
-            for (y in offset.y.toInt() + 1 until offset.y.toInt() + end) {
-                assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isTrue()
-            }
-        }
-    }
-
-    @Test
-    fun isNotWithinSensorArea() {
-        whenever(animationViewController.touchTranslation).thenReturn(PointF(0f, 0f))
-        assertThat(view.isWithinSensorArea(SENSOR_RADIUS * 2.5f, SENSOR_RADIUS.toFloat()))
-            .isFalse()
-        assertThat(view.isWithinSensorArea(SENSOR_RADIUS.toFloat(), SENSOR_RADIUS * 2.5f)).isFalse()
-    }
+    // TODO: Add test to verify view is size of screen
 
     @Test
     fun startAndStopIllumination() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
index 0d17270..2d8adca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -19,7 +19,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
@@ -43,7 +42,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class AlternateBouncerInteractorTest : SysuiTestCase() {
     private lateinit var underTest: AlternateBouncerInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index a9ba36a..915661b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.domain.interactor
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -38,11 +39,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class BouncerInteractorTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
index a81ca86..4aea4f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
@@ -19,7 +19,6 @@
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import org.junit.Before
 import org.junit.Test
@@ -29,7 +28,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class PrimaryBouncerCallbackInteractorTest : SysuiTestCase() {
     private val mPrimaryBouncerCallbackInteractor = PrimaryBouncerCallbackInteractor()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
index cb0b74f..2018e61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
@@ -21,7 +21,6 @@
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.ui.BouncerView
@@ -43,7 +42,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class PrimaryBouncerInteractorWithCoroutinesTest : SysuiTestCase() {
     private lateinit var repository: FakeKeyguardBouncerRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index b5177e1..8e1f5ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -29,10 +30,9 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class AuthMethodBouncerViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index b75355a..2c97809 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
@@ -35,11 +36,10 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class BouncerViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 333bd21..802f8e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -21,7 +21,6 @@
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -50,7 +49,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardBouncerViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index 0926399..ba8dcef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -35,11 +36,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class PasswordBouncerViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index 2e7c9aa..bfaa6ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -38,11 +39,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class PatternBouncerViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 255bbe3..7873899 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -37,11 +38,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class PinBouncerViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
@@ -92,7 +92,7 @@
 
             underTest.onShown()
 
-            assertThat(message?.text).isEqualTo(ENTER_YOUR_PIN)
+            assertThat(message?.text).ignoringCase().isEqualTo(ENTER_YOUR_PIN)
             assertThat(pin).isEmpty()
             assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
             assertThat(underTest.authenticationMethod)
@@ -209,7 +209,7 @@
             underTest.onAuthenticateButtonClicked()
 
             assertThat(pin).isEmpty()
-            assertThat(message?.text).isEqualTo(WRONG_PIN)
+            assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)
             assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
         }
 
@@ -227,7 +227,7 @@
             underTest.onPinButtonClicked(4)
             underTest.onPinButtonClicked(5) // PIN is now wrong!
             underTest.onAuthenticateButtonClicked()
-            assertThat(message?.text).isEqualTo(WRONG_PIN)
+            assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)
             assertThat(pin).isEmpty()
             assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
 
@@ -273,7 +273,7 @@
             ) // PIN is now wrong!
 
             assertThat(pin).isEmpty()
-            assertThat(message?.text).isEqualTo(WRONG_PIN)
+            assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)
             assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt
index 4c279ea..55016bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.bouncer.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.ui.viewmodel.EntryToken.ClearAll
@@ -16,14 +17,13 @@
 import org.junit.Assert.assertThrows
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 /**
  * This test uses a mnemonic code to create and verify PinInput instances: strings of digits [0-9]
  * for [Digit] tokens, as well as a `C` for the [ClearAll] token.
  */
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class PinInputViewModelTest : SysuiTestCase() {
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryImplTest.kt
new file mode 100644
index 0000000..30a5497
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryImplTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 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.communal.data.repository
+
+import android.content.pm.UserInfo
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.FakeLogBuffer
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalTutorialRepositoryImplTest : SysuiTestCase() {
+    private lateinit var secureSettings: FakeSettings
+    private lateinit var userRepository: FakeUserRepository
+    private lateinit var userTracker: FakeUserTracker
+    private lateinit var logBuffer: LogBuffer
+
+    private val testDispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        logBuffer = FakeLogBuffer.Factory.create()
+        secureSettings = FakeSettings()
+        userRepository = FakeUserRepository()
+        val listOfUserInfo = listOf(MAIN_USER_INFO)
+        userRepository.setUserInfos(listOfUserInfo)
+
+        userTracker = FakeUserTracker()
+        userTracker.set(
+            userInfos = listOfUserInfo,
+            selectedUserIndex = 0,
+        )
+    }
+
+    @Test
+    fun tutorialSettingState_defaultToNotStarted() =
+        testScope.runTest {
+            val repository = initCommunalTutorialRepository()
+            val tutorialSettingState = collectLastValue(repository.tutorialSettingState)()
+            assertThat(tutorialSettingState)
+                .isEqualTo(Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED)
+        }
+
+    @Test
+    fun tutorialSettingState_whenTutorialSettingsUpdatedToStarted() =
+        testScope.runTest {
+            val repository = initCommunalTutorialRepository()
+            setTutorialStateSetting(Settings.Secure.HUB_MODE_TUTORIAL_STARTED)
+            val tutorialSettingState = collectLastValue(repository.tutorialSettingState)()
+            assertThat(tutorialSettingState).isEqualTo(Settings.Secure.HUB_MODE_TUTORIAL_STARTED)
+        }
+
+    @Test
+    fun tutorialSettingState_whenTutorialSettingsUpdatedToCompleted() =
+        testScope.runTest {
+            val repository = initCommunalTutorialRepository()
+            setTutorialStateSetting(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
+            val tutorialSettingState = collectLastValue(repository.tutorialSettingState)()
+            assertThat(tutorialSettingState).isEqualTo(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
+        }
+
+    private fun initCommunalTutorialRepository(): CommunalTutorialRepositoryImpl {
+        return CommunalTutorialRepositoryImpl(
+            testScope.backgroundScope,
+            testDispatcher,
+            userRepository,
+            secureSettings,
+            userTracker,
+            logBuffer
+        )
+    }
+
+    private fun setTutorialStateSetting(
+        @Settings.Secure.HubModeTutorialState state: Int,
+        user: UserInfo = MAIN_USER_INFO
+    ) {
+        secureSettings.putIntForUser(Settings.Secure.HUB_MODE_TUTORIAL_STATE, state, user.id)
+    }
+
+    companion object {
+        private val MAIN_USER_INFO =
+            UserInfo(/* id= */ 0, /* name= */ "primary", /* flags= */ UserInfo.FLAG_MAIN)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
index 7fa828f..3df9cbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
@@ -9,7 +9,6 @@
 import android.os.UserManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.coroutines.collectLastValue
@@ -40,7 +39,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
     @Mock private lateinit var appWidgetManager: AppWidgetManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index ddf788e..cdc42e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -19,7 +19,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.repository.FakeCommunalRepository
 import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
@@ -37,7 +36,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class CommunalInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
new file mode 100644
index 0000000..0a9a15e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 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.communal.domain.interactor
+
+import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED
+import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED
+import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_STARTED
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class CommunalTutorialInteractorTest : SysuiTestCase() {
+
+    @Mock private lateinit var userTracker: UserTracker
+
+    private val testDispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private lateinit var underTest: CommunalTutorialInteractor
+    private lateinit var keyguardRepository: FakeKeyguardRepository
+    private lateinit var keyguardInteractor: KeyguardInteractor
+    private lateinit var communalTutorialRepository: FakeCommunalTutorialRepository
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        val withDeps = KeyguardInteractorFactory.create()
+        keyguardInteractor = withDeps.keyguardInteractor
+        keyguardRepository = withDeps.repository
+        communalTutorialRepository = FakeCommunalTutorialRepository()
+
+        underTest =
+            CommunalTutorialInteractor(
+                keyguardInteractor = keyguardInteractor,
+                communalTutorialRepository = communalTutorialRepository,
+            )
+
+        whenever(userTracker.userHandle).thenReturn(mock())
+    }
+
+    @Test
+    fun tutorialUnavailable_whenKeyguardNotVisible() =
+        testScope.runTest {
+            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
+            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
+            keyguardRepository.setKeyguardShowing(false)
+            assertThat(isTutorialAvailable).isFalse()
+        }
+
+    @Test
+    fun tutorialUnavailable_whenTutorialIsCompleted() =
+        testScope.runTest {
+            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+            assertThat(isTutorialAvailable).isFalse()
+        }
+
+    @Test
+    fun tutorialAvailable_whenTutorialNotStarted() =
+        testScope.runTest {
+            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
+            assertThat(isTutorialAvailable).isTrue()
+        }
+
+    @Test
+    fun tutorialAvailable_whenTutorialIsStarted() =
+        testScope.runTest {
+            val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)
+            assertThat(isTutorialAvailable).isTrue()
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
index a10eb29..41a8be9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
@@ -5,7 +5,6 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalWidgetSection
 import org.junit.Before
@@ -15,7 +14,6 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
index 68ea7eb..6c2e136 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
@@ -25,7 +25,7 @@
 import com.android.systemui.demomode.DemoMode.ACTION_DEMO
 import com.android.systemui.demomode.DemoMode.COMMAND_STATUS
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.FakeGlobalSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.launch
@@ -48,7 +48,7 @@
 
     @Mock private lateinit var dumpManager: DumpManager
 
-    private val globalSettings = FakeSettings()
+    private val globalSettings = FakeGlobalSettings()
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt
index 8e8cbe4..2c80035 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt
@@ -1,6 +1,7 @@
 package com.android.systemui.deviceentry.data.repository
 
 import android.content.pm.UserInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
@@ -11,6 +12,7 @@
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.runBlocking
@@ -19,14 +21,14 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 import org.mockito.Mock
 import org.mockito.Mockito
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class DeviceEntryRepositoryTest : SysuiTestCase() {
 
     @Mock private lateinit var lockPatternUtils: LockPatternUtils
@@ -54,6 +56,7 @@
                 keyguardBypassController = keyguardBypassController,
                 keyguardStateController = keyguardStateController,
             )
+        testScope.runCurrent()
     }
 
     @Test
@@ -66,8 +69,7 @@
             assertThat(isUnlocked).isFalse()
 
             val captor = argumentCaptor<KeyguardStateController.Callback>()
-            Mockito.verify(keyguardStateController, Mockito.atLeastOnce())
-                .addCallback(captor.capture())
+            verify(keyguardStateController, Mockito.atLeastOnce()).addCallback(captor.capture())
 
             whenever(keyguardStateController.isUnlocked).thenReturn(true)
             captor.value.onUnlockedChanged()
@@ -98,7 +100,12 @@
         testScope.runTest {
             whenever(keyguardBypassController.isBypassEnabled).thenAnswer { false }
             whenever(keyguardBypassController.bypassEnabled).thenAnswer { false }
-            assertThat(underTest.isBypassEnabled()).isFalse()
+            withArgCaptor {
+                    verify(keyguardBypassController).registerOnBypassStateChangedListener(capture())
+                }
+                .onBypassStateChanged(false)
+            runCurrent()
+            assertThat(underTest.isBypassEnabled.value).isFalse()
         }
 
     @Test
@@ -106,7 +113,12 @@
         testScope.runTest {
             whenever(keyguardBypassController.isBypassEnabled).thenAnswer { true }
             whenever(keyguardBypassController.bypassEnabled).thenAnswer { true }
-            assertThat(underTest.isBypassEnabled()).isTrue()
+            withArgCaptor {
+                    verify(keyguardBypassController).registerOnBypassStateChangedListener(capture())
+                }
+                .onBypassStateChanged(true)
+            runCurrent()
+            assertThat(underTest.isBypassEnabled.value).isTrue()
         }
 
     companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
index 55582e1..c13fde7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.deviceentry.domain.interactor
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -14,11 +15,10 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class DeviceEntryInteractorTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
@@ -218,14 +218,14 @@
     fun isBypassEnabled_enabledInRepository_true() =
         testScope.runTest {
             utils.deviceEntryRepository.setBypassEnabled(true)
-            assertThat(underTest.isBypassEnabled()).isTrue()
+            assertThat(underTest.isBypassEnabled.value).isTrue()
         }
 
     @Test
     fun isBypassEnabled_disabledInRepository_false() =
         testScope.runTest {
             utils.deviceEntryRepository.setBypassEnabled(false)
-            assertThat(underTest.isBypassEnabled()).isFalse()
+            assertThat(underTest.isBypassEnabled.value).isFalse()
         }
 
     private fun switchToScene(sceneKey: SceneKey) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 781ad6b..8a35ef1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -6,7 +6,6 @@
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.complication.ComplicationHostViewController
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
@@ -30,7 +29,6 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
index 21192fa..2c6c793 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
@@ -17,7 +17,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -30,7 +29,6 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class DreamOverlayCallbackControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 7c36642..2af6566 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -38,7 +38,6 @@
 
 import com.android.dream.lowlight.LowLightTransitionCoordinator;
 import com.android.keyguard.BouncerPanelExpansionCalculator;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
@@ -53,7 +52,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
index be7638e..d379dc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
@@ -26,7 +26,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
@@ -38,7 +37,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 8379f73..e5f9972 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -49,7 +49,6 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.ComplicationLayoutEngine;
 import com.android.systemui.dreams.complication.HideComplicationTouchHandler;
@@ -72,7 +71,6 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayServiceTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 2ef227c..365f67b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -29,7 +29,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.Complication;
 import com.android.systemui.flags.FeatureFlags;
@@ -48,7 +47,6 @@
 
 import java.util.Collection;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayStateControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
index 12cb332..7ff345c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
@@ -24,7 +24,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -36,7 +35,6 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayStatusBarItemsProviderTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 9566e81..39db2be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -46,11 +46,10 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.res.R;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.core.FakeLogBuffer;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
@@ -72,7 +71,6 @@
 import java.util.Optional;
 import java.util.concurrent.Executor;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
index d32788d..315a24b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
@@ -30,7 +30,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.Complication;
 import com.android.systemui.dreams.DreamOverlayStateController;
@@ -49,7 +48,6 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class HideComplicationTouchHandlerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
index 4a7700f..e0c6ab2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
@@ -26,7 +26,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener;
@@ -41,7 +40,6 @@
 
 import kotlinx.coroutines.CoroutineScope;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class AssistantAttentionConditionTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
index cd2efde..480754c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -31,7 +31,6 @@
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shared.condition.Condition;
 
@@ -44,7 +43,6 @@
 
 import kotlinx.coroutines.CoroutineScope;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamConditionTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index ffcaeee..3d1efa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.dreams.touch;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -40,7 +41,6 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
 import com.android.systemui.dreams.touch.scrim.ScrimController;
@@ -64,7 +64,6 @@
 import java.util.Collections;
 import java.util.Optional;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
index ff6d97d..6aa821f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
@@ -27,7 +27,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.shared.system.InputChannelCompat;
@@ -43,7 +42,6 @@
 
 import java.util.Optional;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ShadeTouchHandlerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
index da39381..017fdbe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
@@ -26,7 +26,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -38,7 +37,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BouncerlessScrimControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
index 81f6fe3..4ee4a60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
@@ -25,7 +25,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -38,7 +37,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ScrimManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
index 14c5ec0..c12a581 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
@@ -36,7 +36,6 @@
 import org.junit.Assert
 import org.junit.Before
 import org.junit.Test
-import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.anyString
@@ -479,7 +478,7 @@
                 verify(flagManager, times(numReads))
                     .readFlagValue(eq(name), any<FlagSerializer<*>>())
                 verify(flagManager).nameToSettingsKey(eq(name))
-                verify(globalSettings).putStringForUser(eq("key-$name"), eq(data), anyInt())
+                verify(globalSettings).putString(eq("key-$name"), eq(data))
                 verify(flagManager).dispatchListenersAndMaybeRestart(eq(name), any())
             }
             .verifyNoMoreInteractions()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index b1cf051..2d3f69d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -78,6 +78,8 @@
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.util.RingerModeLiveData;
 import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.settings.FakeGlobalSettings;
+import com.android.systemui.util.settings.FakeSettings;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -105,8 +107,8 @@
     @Mock private LockPatternUtils mLockPatternUtils;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
     @Mock private TelephonyListenerManager mTelephonyListenerManager;
-    @Mock private GlobalSettings mGlobalSettings;
-    @Mock private SecureSettings mSecureSettings;
+    private GlobalSettings mGlobalSettings;
+    private SecureSettings mSecureSettings;
     @Mock private Resources mResources;
     @Mock private ConfigurationController mConfigurationController;
     @Mock private UserTracker mUserTracker;
@@ -148,6 +150,9 @@
         when(mResources.getConfiguration()).thenReturn(
                 getContext().getResources().getConfiguration());
 
+        mGlobalSettings = new FakeGlobalSettings();
+        mSecureSettings = new FakeSettings();
+
         mGlobalActionsDialogLite = new GlobalActionsDialogLite(mContext,
                 mWindowManagerFuncs,
                 mAudioManager,
@@ -592,8 +597,8 @@
         UserInfo currentUser = mockCurrentUser(FLAG_ADMIN);
 
         when(mGlobalActionsDialogLite.getCurrentUser()).thenReturn(currentUser);
-        when(mGlobalSettings.getIntForUser(Settings.Secure.BUGREPORT_IN_POWER_MENU,
-                0, currentUser.id)).thenReturn(1);
+        mSecureSettings.putIntForUser(Settings.Secure.BUGREPORT_IN_POWER_MENU, 1,
+                currentUser.id);
 
         GlobalActionsDialogLite.BugReportAction bugReportAction =
                 mGlobalActionsDialogLite.makeBugReportActionForTesting();
@@ -605,8 +610,8 @@
         UserInfo currentUser = mockCurrentUser(0);
 
         when(mGlobalActionsDialogLite.getCurrentUser()).thenReturn(currentUser);
-        doReturn(1).when(mGlobalSettings)
-                .getIntForUser(Settings.Secure.BUGREPORT_IN_POWER_MENU, 0, currentUser.id);
+        mSecureSettings.putIntForUser(Settings.Secure.BUGREPORT_IN_POWER_MENU, 1,
+                currentUser.id);
 
         GlobalActionsDialogLite.BugReportAction bugReportAction =
                 mGlobalActionsDialogLite.makeBugReportActionForTesting();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
index 632d149..f373062 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
@@ -16,23 +16,17 @@
 
 package com.android.systemui.keyevent.domain.interactor
 
-import android.view.KeyEvent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.back.domain.interactor.BackActionInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
-import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyevent.data.repository.FakeKeyEventRepository
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
 
 @SmallTest
@@ -40,108 +34,27 @@
 class KeyEventInteractorTest : SysuiTestCase() {
     @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
 
-    private lateinit var keyguardInteractorWithDependencies:
-        KeyguardInteractorFactory.WithDependencies
-    @Mock private lateinit var keyguardKeyEventInteractor: KeyguardKeyEventInteractor
-    @Mock private lateinit var backActionInteractor: BackActionInteractor
+    private lateinit var repository: FakeKeyEventRepository
 
     private lateinit var underTest: KeyEventInteractor
 
     @Before
     fun setup() {
-        keyguardInteractorWithDependencies = KeyguardInteractorFactory.create()
+        repository = FakeKeyEventRepository()
         underTest =
             KeyEventInteractor(
-                backActionInteractor,
-                keyguardKeyEventInteractor,
+                repository,
             )
     }
 
     @Test
-    fun dispatchBackKey_notHandledByKeyguardKeyEventInteractor_handledByBackActionInteractor() {
-        val backKeyEventActionDown = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)
-        val backKeyEventActionUp = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)
+    fun dispatchBackKey_notHandledByKeyguardKeyEventInteractor_handledByBackActionInteractor() =
+        runTest {
+            val isPowerDown by collectLastValue(underTest.isPowerButtonDown)
+            repository.setPowerButtonDown(false)
+            assertThat(isPowerDown).isFalse()
 
-        // GIVEN back key ACTION_DOWN and ACTION_UP aren't handled by the keyguardKeyEventInteractor
-        whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionDown))
-            .thenReturn(false)
-        whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionUp))
-            .thenReturn(false)
-
-        // WHEN back key event ACTION_DOWN, the event is handled even though back isn't requested
-        assertThat(underTest.dispatchKeyEvent(backKeyEventActionDown)).isTrue()
-        // THEN back event isn't handled on ACTION_DOWN
-        verify(backActionInteractor, never()).onBackRequested()
-
-        // WHEN back key event ACTION_UP
-        assertThat(underTest.dispatchKeyEvent(backKeyEventActionUp)).isTrue()
-        // THEN back event is handled on ACTION_UP
-        verify(backActionInteractor).onBackRequested()
-    }
-
-    @Test
-    fun dispatchKeyEvent_isNotHandledByKeyguardKeyEventInteractor() {
-        val keyEvent =
-            KeyEvent(
-                KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_SPACE,
-            )
-        whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(false)
-        assertThat(underTest.dispatchKeyEvent(keyEvent)).isFalse()
-    }
-
-    @Test
-    fun dispatchKeyEvent_handledByKeyguardKeyEventInteractor() {
-        val keyEvent =
-            KeyEvent(
-                KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_SPACE,
-            )
-        whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(true)
-        assertThat(underTest.dispatchKeyEvent(keyEvent)).isTrue()
-    }
-
-    @Test
-    fun interceptMediaKey_isNotHandledByKeyguardKeyEventInteractor() {
-        val keyEvent =
-            KeyEvent(
-                KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_SPACE,
-            )
-        whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(false)
-        assertThat(underTest.interceptMediaKey(keyEvent)).isFalse()
-    }
-
-    @Test
-    fun interceptMediaKey_handledByKeyguardKeyEventInteractor() {
-        val keyEvent =
-            KeyEvent(
-                KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_SPACE,
-            )
-        whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(true)
-        assertThat(underTest.interceptMediaKey(keyEvent)).isTrue()
-    }
-
-    @Test
-    fun dispatchKeyEventPreIme_isNotHandledByKeyguardKeyEventInteractor() {
-        val keyEvent =
-            KeyEvent(
-                KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_SPACE,
-            )
-        whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(false)
-        assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isFalse()
-    }
-
-    @Test
-    fun dispatchKeyEventPreIme_handledByKeyguardKeyEventInteractor() {
-        val keyEvent =
-            KeyEvent(
-                KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_SPACE,
-            )
-        whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(true)
-        assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isTrue()
-    }
+            repository.setPowerButtonDown(true)
+            assertThat(isPowerDown).isTrue()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt
new file mode 100644
index 0000000..af00a48
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2023 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.keyevent.domain.interactor
+
+import android.view.KeyEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.back.domain.interactor.BackActionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SysUIKeyEventHandlerTest : SysuiTestCase() {
+    @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+    private lateinit var keyguardInteractorWithDependencies:
+        KeyguardInteractorFactory.WithDependencies
+    @Mock private lateinit var keyguardKeyEventInteractor: KeyguardKeyEventInteractor
+    @Mock private lateinit var backActionInteractor: BackActionInteractor
+
+    private lateinit var underTest: SysUIKeyEventHandler
+
+    @Before
+    fun setup() {
+        keyguardInteractorWithDependencies = KeyguardInteractorFactory.create()
+        underTest =
+            SysUIKeyEventHandler(
+                backActionInteractor,
+                keyguardKeyEventInteractor,
+            )
+    }
+
+    @Test
+    fun dispatchBackKey_notHandledByKeyguardKeyEventInteractor_handledByBackActionInteractor() {
+        val backKeyEventActionDown = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)
+        val backKeyEventActionUp = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)
+
+        // GIVEN back key ACTION_DOWN and ACTION_UP aren't handled by the keyguardKeyEventInteractor
+        whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionDown))
+            .thenReturn(false)
+        whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionUp))
+            .thenReturn(false)
+
+        // WHEN back key event ACTION_DOWN, the event is handled even though back isn't requested
+        assertThat(underTest.dispatchKeyEvent(backKeyEventActionDown)).isTrue()
+        // THEN back event isn't handled on ACTION_DOWN
+        verify(backActionInteractor, never()).onBackRequested()
+
+        // WHEN back key event ACTION_UP
+        assertThat(underTest.dispatchKeyEvent(backKeyEventActionUp)).isTrue()
+        // THEN back event is handled on ACTION_UP
+        verify(backActionInteractor).onBackRequested()
+    }
+
+    @Test
+    fun dispatchKeyEvent_isNotHandledByKeyguardKeyEventInteractor() {
+        val keyEvent =
+            KeyEvent(
+                KeyEvent.ACTION_UP,
+                KeyEvent.KEYCODE_SPACE,
+            )
+        whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(false)
+        assertThat(underTest.dispatchKeyEvent(keyEvent)).isFalse()
+    }
+
+    @Test
+    fun dispatchKeyEvent_handledByKeyguardKeyEventInteractor() {
+        val keyEvent =
+            KeyEvent(
+                KeyEvent.ACTION_UP,
+                KeyEvent.KEYCODE_SPACE,
+            )
+        whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(true)
+        assertThat(underTest.dispatchKeyEvent(keyEvent)).isTrue()
+    }
+
+    @Test
+    fun interceptMediaKey_isNotHandledByKeyguardKeyEventInteractor() {
+        val keyEvent =
+            KeyEvent(
+                KeyEvent.ACTION_UP,
+                KeyEvent.KEYCODE_SPACE,
+            )
+        whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(false)
+        assertThat(underTest.interceptMediaKey(keyEvent)).isFalse()
+    }
+
+    @Test
+    fun interceptMediaKey_handledByKeyguardKeyEventInteractor() {
+        val keyEvent =
+            KeyEvent(
+                KeyEvent.ACTION_UP,
+                KeyEvent.KEYCODE_SPACE,
+            )
+        whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(true)
+        assertThat(underTest.interceptMediaKey(keyEvent)).isTrue()
+    }
+
+    @Test
+    fun dispatchKeyEventPreIme_isNotHandledByKeyguardKeyEventInteractor() {
+        val keyEvent =
+            KeyEvent(
+                KeyEvent.ACTION_UP,
+                KeyEvent.KEYCODE_SPACE,
+            )
+        whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(false)
+        assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isFalse()
+    }
+
+    @Test
+    fun dispatchKeyEventPreIme_handledByKeyguardKeyEventInteractor() {
+        val keyEvent =
+            KeyEvent(
+                KeyEvent.ACTION_UP,
+                KeyEvent.KEYCODE_SPACE,
+            )
+        whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(true)
+        assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isTrue()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 291dda20..a646823 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.keyguard;
 
-import static android.os.PowerManager.WAKE_REASON_WAKE_MOTION;
 import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT;
@@ -635,29 +634,6 @@
     }
 
     @Test
-    public void lockAfterSpecifiedAfterDreamStarted() {
-        int currentUserId = 99;
-        int userSpecificTimeout = 5999;
-        KeyguardUpdateMonitor.setCurrentUser(currentUserId);
-
-        // set mDeviceInteractive to true
-        mViewMediator.onStartedWakingUp(WAKE_REASON_WAKE_MOTION, false);
-        mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, false);
-        when(mLockPatternUtils.isSecure(currentUserId)).thenReturn(true);
-        when(mDevicePolicyManager.getMaximumTimeToLock(null, currentUserId)).thenReturn(0L);
-        when(mSecureSettings.getIntForUser(LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
-                KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, currentUserId)).thenReturn(userSpecificTimeout);
-        mSystemClock.setElapsedRealtime(0L);
-        ArgumentCaptor<PendingIntent> pendingIntent = ArgumentCaptor.forClass(PendingIntent.class);
-
-        mViewMediator.onDreamingStarted();
-
-        verify(mAlarmManager).setExactAndAllowWhileIdle(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
-                eq(Long.valueOf(userSpecificTimeout)), pendingIntent.capture());
-        assertEquals(DELAYED_KEYGUARD_ACTION, pendingIntent.getValue().getIntent().getAction());
-    }
-
-    @Test
     public void testHideSurfaceBehindKeyguardMarksKeyguardNotGoingAway() {
         mViewMediator.hideSurfaceBehindKeyguard();
 
@@ -1023,7 +999,6 @@
         mViewMediator.setShowingLocked(false);
         when(mKeyguardStateController.isShowing()).thenReturn(false);
 
-        mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, false);
         mViewMediator.onDreamingStarted();
         assertFalse(mViewMediator.isShowingAndNotOccluded());
     }
@@ -1034,7 +1009,6 @@
         mViewMediator.setShowingLocked(true);
         when(mKeyguardStateController.isShowing()).thenReturn(true);
 
-        mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, true);
         mViewMediator.onDreamingStarted();
         assertTrue(mViewMediator.isShowingAndNotOccluded());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
index cfee3b8..e20d3af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
@@ -23,7 +23,6 @@
 import android.content.pm.PackageManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.camera.CameraGestureHelper
 import com.android.systemui.settings.UserTracker
@@ -43,7 +42,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CameraQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
index 49168d0..977f1db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
@@ -25,14 +25,13 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.notification.EnableZenModeDialog
-import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.ZenModeController
 import com.android.systemui.util.mockito.argumentCaptor
@@ -61,7 +60,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
index c85c7f6..548b564 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
@@ -17,7 +17,6 @@
 
 package com.android.systemui.keyguard.data.quickaffordance
 
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.animation.Expandable
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
 import kotlinx.coroutines.flow.Flow
@@ -25,7 +24,6 @@
 import kotlinx.coroutines.yield
 
 /** Fake implementation of a quick affordance data source. */
-@RoboPilotTest
 class FakeKeyguardQuickAffordanceConfig(
     override val key: String,
     private val pickerName: String = key,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
index c3e28ae..4ae144c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
@@ -21,7 +21,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
 import com.android.systemui.statusbar.policy.FlashlightController
@@ -42,7 +41,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index ef56a98..7d68cc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -20,7 +20,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Expandable
 import com.android.systemui.controls.controller.ControlsController
@@ -41,7 +40,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
index 4f071bd..26fcb23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
@@ -22,9 +22,8 @@
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
 import com.android.systemui.util.FakeSharedPreferences
@@ -49,7 +48,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceLegacySettingSyncerTest : SysuiTestCase() {
 
@@ -72,8 +70,7 @@
         val resources: Resources = mock()
         whenever(resources.getStringArray(R.array.config_keyguardQuickAffordanceDefaults))
             .thenReturn(emptyArray())
-        whenever(resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled))
-            .thenReturn(true)
+        whenever(resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled)).thenReturn(true)
         whenever(context.resources).thenReturn(resources)
 
         testDispatcher = UnconfinedTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
index bd0b71d..99a0185 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
@@ -23,7 +23,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.backup.BackupHelper
 import com.android.systemui.settings.FakeUserTracker
@@ -53,7 +52,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
index 0797d07..a1c9f87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
@@ -21,7 +21,6 @@
 import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient
@@ -44,7 +43,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
index d8c0341..b15352b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
@@ -21,7 +21,6 @@
 import android.media.AudioManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
@@ -46,7 +45,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class MuteQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index 9d983b8..521dea3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -20,7 +20,6 @@
 import android.content.Intent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
@@ -40,7 +39,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index 613c4ce..02db0d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -24,7 +24,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.animation.Expandable
@@ -51,7 +50,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
index 1414bac..a9b9c90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
@@ -21,7 +21,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.ActivityIntentHelper
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.camera.CameraIntentsWrapper
 import com.android.systemui.coroutines.collectLastValue
@@ -45,7 +44,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
index 944b059..d8cdf29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
@@ -32,7 +32,6 @@
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.biometrics.data.repository.FaceSensorInfo
@@ -79,7 +78,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @RunWith(AndroidJUnit4::class)
 class BiometricSettingsRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 307204da..819d08a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -44,7 +44,6 @@
 import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
@@ -122,7 +121,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
     private lateinit var underTest: DeviceEntryFaceAuthRepositoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index def016a..a58bc52 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -22,7 +22,6 @@
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.coroutines.collectLastValue
@@ -49,7 +48,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
index 7eb8a26..9be5558 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.shared.model.DevicePosture
@@ -39,7 +38,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DevicePostureRepositoryTest : SysuiTestCase() {
     private lateinit var underTest: DevicePostureRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
index 126b841..567e0a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
@@ -22,7 +22,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
@@ -56,7 +55,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 7983e30..b9119e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -22,7 +22,6 @@
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.common.shared.model.Position
@@ -64,7 +63,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardRepositoryImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
index 4942cf8..799bd5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -20,7 +20,6 @@
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
 import com.android.systemui.coroutines.collectLastValue
@@ -46,7 +45,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class LightRevealScrimRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
index 7f784d8..ee47c58f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
@@ -21,7 +21,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.logging.TrustRepositoryLogger
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.FlowValue
 import com.android.systemui.coroutines.collectLastValue
@@ -46,7 +45,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class TrustRepositoryTest : SysuiTestCase() {
     @Mock private lateinit var trustManager: TrustManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index 181cc88..d6e19cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -19,7 +19,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -43,7 +42,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardDismissActionInteractorTest : SysuiTestCase() {
     private lateinit var keyguardRepository: FakeKeyguardRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
index c407b14..a5cfbbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
@@ -22,7 +22,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.TrustGrantFlags
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.shared.model.DismissAction
@@ -40,7 +39,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardDismissInteractorTest : SysuiTestCase() {
     private lateinit var dispatcher: TestDispatcher
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index b527510..06eb0dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -28,8 +28,10 @@
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FaceSensorInfo
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
 import com.android.systemui.biometrics.shared.model.LockoutMode
+import com.android.systemui.biometrics.shared.model.SensorStrength
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -156,7 +158,6 @@
                 fakeDeviceEntryFingerprintAuthRepository,
                 fakeUserRepository,
                 facePropertyRepository,
-                fakeKeyguardRepository,
                 faceWakeUpTriggersConfig,
                 powerInteractor,
             )
@@ -440,6 +441,43 @@
         }
 
     @Test
+    fun faceAuthIsRequestedWhenWalletIsLaunchedAndIfFaceAuthIsStrong() =
+        testScope.runTest {
+            underTest.start()
+            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
+
+            underTest.onWalletLaunched()
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value)
+                .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED, true))
+        }
+
+    @Test
+    fun faceAuthIsNotTriggeredIfFaceAuthIsWeak() =
+        testScope.runTest {
+            underTest.start()
+            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.WEAK))
+
+            underTest.onWalletLaunched()
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+        }
+
+    @Test
+    fun faceAuthIsNotTriggeredIfFaceAuthIsConvenience() =
+        testScope.runTest {
+            underTest.start()
+            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.CONVENIENCE))
+
+            underTest.onWalletLaunched()
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+        }
+
+    @Test
     fun faceUnlockIsDisabledWhenFpIsLockedOut() =
         testScope.runTest {
             underTest.start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index ca52cdb..b32905f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -20,7 +20,6 @@
 import android.app.StatusBarManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
@@ -47,7 +46,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
index bbe6823..a5d7457 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
@@ -57,8 +57,6 @@
         KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
     private val backKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)
 
-    private lateinit var keyguardInteractorWithDependencies:
-        KeyguardInteractorFactory.WithDependencies
     private lateinit var powerInteractor: PowerInteractor
     @Mock private lateinit var statusBarStateController: StatusBarStateController
     @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
@@ -73,14 +71,12 @@
     fun setup() {
         whenever(mediaSessionLegacyHelperWrapper.getHelper(any()))
             .thenReturn(mediaSessionLegacyHelper)
-        keyguardInteractorWithDependencies = KeyguardInteractorFactory.create()
         powerInteractor = PowerInteractorFactory.create().powerInteractor
 
         underTest =
             KeyguardKeyEventInteractor(
                 context,
                 statusBarStateController,
-                keyguardInteractorWithDependencies.keyguardInteractor,
                 statusBarKeyguardViewManager,
                 shadeController,
                 mediaSessionLegacyHelperWrapper,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
index 13025a0..0c74a38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -22,7 +22,6 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.FakeFeatureFlags
@@ -51,7 +50,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardLongPressInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 8c13bb4..347d580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -23,7 +23,6 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.DialogLaunchAnimator
 import com.android.systemui.common.shared.model.ContentDescription
@@ -73,7 +72,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
index fdcc66b..71fcf6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
@@ -41,7 +40,6 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index 9e9c25e..29b546b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -19,7 +19,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -42,7 +41,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardTransitionInteractorTest : SysuiTestCase() {
@@ -230,4 +228,432 @@
 
         assertThat(startedSteps).isEqualTo(listOf(0f, 0.5f, 1f, 1f, 0.5f, 0f))
     }
+
+    @Test
+    fun isInTransitionToState() = testScope.runTest {
+        val results by collectValues(underTest.isInTransitionToState(GONE))
+
+        sendSteps(
+                TransitionStep(AOD, DOZING, 0f, STARTED),
+                TransitionStep(AOD, DOZING, 0.5f, RUNNING),
+                TransitionStep(AOD, DOZING, 1f, FINISHED),
+        )
+
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(GONE, DOZING, 0f, STARTED),
+                TransitionStep(GONE, DOZING, 0f, RUNNING),
+                TransitionStep(GONE, DOZING, 1f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+                true,
+        ))
+    }
+
+    @Test
+    fun isInTransitionFromState() = testScope.runTest {
+        val results by collectValues(underTest.isInTransitionFromState(DOZING))
+
+        sendSteps(
+                TransitionStep(AOD, DOZING, 0f, STARTED),
+                TransitionStep(AOD, DOZING, 0.5f, RUNNING),
+                TransitionStep(AOD, DOZING, 1f, FINISHED),
+        )
+
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(GONE, DOZING, 0f, STARTED),
+                TransitionStep(GONE, DOZING, 0f, RUNNING),
+                TransitionStep(GONE, DOZING, 1f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+                true,
+        ))
+    }
+
+    @Test
+    fun isInTransitionFromStateWhere() = testScope.runTest {
+        val results by collectValues(underTest.isInTransitionFromStateWhere {
+            it == DOZING
+        })
+
+        sendSteps(
+                TransitionStep(AOD, DOZING, 0f, STARTED),
+                TransitionStep(AOD, DOZING, 0.5f, RUNNING),
+                TransitionStep(AOD, DOZING, 1f, FINISHED),
+        )
+
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(GONE, DOZING, 0f, STARTED),
+                TransitionStep(GONE, DOZING, 0f, RUNNING),
+                TransitionStep(GONE, DOZING, 1f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+                true,
+        ))
+    }
+
+    @Test
+    fun isInTransitionWhere() = testScope.runTest {
+        val results by collectValues(underTest.isInTransitionWhere(
+            fromStatePredicate = { it == DOZING },
+            toStatePredicate = { it == GONE },
+        ))
+
+        sendSteps(
+                TransitionStep(AOD, DOZING, 0f, STARTED),
+                TransitionStep(AOD, DOZING, 0.5f, RUNNING),
+                TransitionStep(AOD, DOZING, 1f, FINISHED),
+        )
+
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(GONE, DOZING, 0f, STARTED),
+                TransitionStep(GONE, DOZING, 0f, RUNNING),
+                TransitionStep(GONE, DOZING, 1f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+                true,
+        ))
+    }
+
+    @Test
+    fun isFinishedInStateWhere() = testScope.runTest {
+        val results by collectValues(underTest.isFinishedInStateWhere { it == GONE } )
+
+        sendSteps(
+                TransitionStep(AOD, DOZING, 0f, STARTED),
+                TransitionStep(AOD, DOZING, 0.5f, RUNNING),
+                TransitionStep(AOD, DOZING, 1f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false, // Finished in DOZING, not GONE.
+        ))
+
+        sendSteps(TransitionStep(DOZING, GONE, 0f, STARTED))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+        ))
+
+        sendSteps(TransitionStep(DOZING, GONE, 0f, RUNNING))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+        ))
+
+        sendSteps(TransitionStep(DOZING, GONE, 1f, FINISHED))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(GONE, DOZING, 0f, STARTED),
+                TransitionStep(GONE, DOZING, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(TransitionStep(GONE, DOZING, 1f, FINISHED))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(TransitionStep(DOZING, GONE, 1f, FINISHED))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+                true,
+        ))
+    }
+
+    @Test
+    fun isFinishedInState() = testScope.runTest {
+        val results by collectValues(underTest.isFinishedInState(GONE))
+
+        sendSteps(
+                TransitionStep(AOD, DOZING, 0f, STARTED),
+                TransitionStep(AOD, DOZING, 0.5f, RUNNING),
+                TransitionStep(AOD, DOZING, 1f, FINISHED),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false, // Finished in DOZING, not GONE.
+        ))
+
+        sendSteps(TransitionStep(DOZING, GONE, 0f, STARTED))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+        ))
+
+        sendSteps(TransitionStep(DOZING, GONE, 0f, RUNNING))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+        ))
+
+        sendSteps(TransitionStep(DOZING, GONE, 1f, FINISHED))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(
+                TransitionStep(GONE, DOZING, 0f, STARTED),
+                TransitionStep(GONE, DOZING, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+        ))
+
+        sendSteps(TransitionStep(GONE, DOZING, 1f, FINISHED))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(
+                TransitionStep(DOZING, GONE, 0f, STARTED),
+                TransitionStep(DOZING, GONE, 0f, RUNNING),
+        )
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+        ))
+
+        sendSteps(TransitionStep(DOZING, GONE, 1f, FINISHED))
+
+        assertThat(results).isEqualTo(listOf(
+                false,
+                true,
+                false,
+                true,
+        ))
+    }
+
+    private suspend fun sendSteps(vararg steps: TransitionStep) {
+        steps.forEach {
+            repository.sendTransitionStep(it)
+            testScope.runCurrent()
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index 906d948..c02add1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository
@@ -45,7 +44,6 @@
 import org.mockito.Spy
 
 @SmallTest
-@RoboPilotTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class LightRevealScrimInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index 73ecae5..16f2fa2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -38,7 +37,6 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
index a22f603..5b29a86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
@@ -20,7 +20,6 @@
 import android.view.RemoteAnimationTarget
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardViewController
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
 import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor
@@ -41,7 +40,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWithLooper(setAsMainLooper = true)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardSurfaceBehindParamsApplierTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 7a17435..9b2db3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -19,7 +19,6 @@
 import android.app.IActivityTaskManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -35,7 +34,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
index 7940b45..50ee026 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
@@ -23,6 +23,7 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.ui.view.layout.sections.CommunalTutorialIndicatorSection
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.shared.model.KeyguardSection
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
@@ -65,6 +66,7 @@
     @Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines
     @Mock private lateinit var aodNotificationIconsSection: AodNotificationIconsSection
     @Mock private lateinit var aodBurnInSection: AodBurnInSection
+    @Mock private lateinit var communalTutorialIndicatorSection: CommunalTutorialIndicatorSection
 
     @Before
     fun setup() {
@@ -83,6 +85,7 @@
                 splitShadeGuidelines,
                 aodNotificationIconsSection,
                 aodBurnInSection,
+                communalTutorialIndicatorSection,
             )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
new file mode 100644
index 0000000..1768f8c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@ExperimentalCoroutinesApi
+@RunWith(JUnit4::class)
+@SmallTest
+class AlternateBouncerViewModelTest : SysuiTestCase() {
+
+    private lateinit var testScope: TestScope
+
+    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+    @Mock private lateinit var falsingManager: FalsingManager
+
+    private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var transitionInteractor: KeyguardTransitionInteractor
+    private lateinit var underTest: AlternateBouncerViewModel
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        testScope = TestScope()
+
+        val transitionInteractorWithDependencies =
+            KeyguardTransitionInteractorFactory.create(testScope.backgroundScope)
+        transitionInteractor = transitionInteractorWithDependencies.keyguardTransitionInteractor
+        transitionRepository = transitionInteractorWithDependencies.repository
+        underTest =
+            AlternateBouncerViewModel(
+                statusBarKeyguardViewManager,
+                transitionInteractor,
+                falsingManager,
+            )
+    }
+
+    @Test
+    fun transitionToAlternateBouncer_scrimAlphaUpdate() =
+        runTest(UnconfinedTestDispatcher()) {
+            val scrimAlphas by collectValues(underTest.scrimAlpha)
+
+            transitionRepository.sendTransitionStep(
+                stepToAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.4f))
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f))
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f))
+
+            assertThat(scrimAlphas.size).isEqualTo(4)
+            scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+        }
+
+    @Test
+    fun transitionFromAlternateBouncer_scrimAlphaUpdate() =
+        runTest(UnconfinedTestDispatcher()) {
+            val scrimAlphas by collectValues(underTest.scrimAlpha)
+
+            transitionRepository.sendTransitionStep(
+                stepFromAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.4f))
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f))
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f))
+
+            assertThat(scrimAlphas.size).isEqualTo(4)
+            scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+        }
+
+    @Test
+    fun clickListenerUpdate() =
+        runTest(UnconfinedTestDispatcher()) {
+            val clickListener by collectLastValue(underTest.onClickListener)
+
+            // keyguard state => ALTERNATE_BOUNCER
+            transitionRepository.sendTransitionStep(
+                stepToAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f))
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f))
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f))
+            assertThat(clickListener).isNotNull()
+
+            // ALTERNATE_BOUNCER -> keyguard state
+            transitionRepository.sendTransitionStep(
+                stepFromAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            assertThat(clickListener).isNotNull()
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f))
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f))
+            assertThat(clickListener).isNull()
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f))
+            assertThat(clickListener).isNull()
+        }
+
+    @Test
+    fun forcePluginOpen() =
+        runTest(UnconfinedTestDispatcher()) {
+            val forcePluginOpen by collectLastValue(underTest.forcePluginOpen)
+            transitionRepository.sendTransitionStep(
+                stepToAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f))
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f))
+            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f))
+            assertThat(forcePluginOpen).isTrue()
+
+            transitionRepository.sendTransitionStep(
+                stepFromAlternateBouncer(0f, TransitionState.STARTED)
+            )
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f))
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f))
+            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f))
+            assertThat(forcePluginOpen).isFalse()
+        }
+
+    private fun stepToAlternateBouncer(
+        value: Float,
+        state: TransitionState = TransitionState.RUNNING
+    ): TransitionStep {
+        return step(
+            from = KeyguardState.LOCKSCREEN,
+            to = KeyguardState.ALTERNATE_BOUNCER,
+            value = value,
+            transitionState = state,
+        )
+    }
+
+    private fun stepFromAlternateBouncer(
+        value: Float,
+        state: TransitionState = TransitionState.RUNNING
+    ): TransitionStep {
+        return step(
+            from = KeyguardState.ALTERNATE_BOUNCER,
+            to = KeyguardState.LOCKSCREEN,
+            value = value,
+            transitionState = state,
+        )
+    }
+
+    private fun step(
+        from: KeyguardState,
+        to: KeyguardState,
+        value: Float,
+        transitionState: TransitionState
+    ): TransitionStep {
+        return TransitionStep(
+            from = from,
+            to = to,
+            value = value,
+            transitionState = transitionState,
+            ownerName = "AlternateBouncerViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
index bfc6f31..6d47aed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -46,7 +45,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: DreamingToLockscreenTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
index 75c8bff..cf20129 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -37,7 +36,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class GoneToDreamingTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: GoneToDreamingTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 6e94691..7de28de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -28,10 +29,9 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class LockscreenSceneViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
index 12fe07f..89a1d2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -37,7 +36,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: LockscreenToDreamingTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
index 83ae631..41f8856 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -37,7 +36,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: LockscreenToOccludedTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
index 8860399..ec95cb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
@@ -37,7 +36,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: OccludedToLockscreenTransitionViewModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index da372ea..d7802aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.coroutines.collectValues
@@ -46,7 +45,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel
@@ -62,10 +60,7 @@
         MockitoAnnotations.initMocks(this)
         repository = FakeKeyguardTransitionRepository()
         val featureFlags =
-            FakeFeatureFlags().apply {
-                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
-                set(Flags.UDFPS_NEW_TOUCH_DETECTION, true)
-            }
+            FakeFeatureFlags().apply { set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) }
         val interactor =
             KeyguardTransitionInteractorFactory.create(
                     scope = TestScope().backgroundScope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
index 9ab9b3d..32acefe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
@@ -46,7 +45,6 @@
 
 @ExperimentalCoroutinesApi
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class UdfpsAodViewModelTest : SysuiTestCase() {
     private val defaultPadding = 12
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index fb0a4be..59d8104 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -48,7 +48,6 @@
 import com.android.internal.logging.InstanceId
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.InstanceIdSequenceFake
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dump.DumpManager
@@ -63,6 +62,7 @@
 import com.android.systemui.media.controls.util.MediaFlags
 import com.android.systemui.media.controls.util.MediaUiEventLogger
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.SbnBuilder
 import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -2204,6 +2204,85 @@
     }
 
     @Test
+    fun testSessionPlayer_sessionDestroyed_noResume_fullyRemoved() {
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
+        addPlaybackStateAction()
+
+        // When a media control with PlaybackState actions is added, times out,
+        // and then the session is destroyed
+        addNotificationAndLoad()
+        val data = mediaDataCaptor.value
+        assertThat(data.active).isTrue()
+        mediaDataManager.setTimedOut(KEY, timedOut = true)
+        sessionCallbackCaptor.value.invoke(KEY)
+
+        // It is fully removed.
+        verify(listener).onMediaDataRemoved(eq(KEY))
+        verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
+        verify(listener, never())
+            .onMediaDataLoaded(
+                eq(PACKAGE_NAME),
+                eq(KEY),
+                capture(mediaDataCaptor),
+                eq(true),
+                eq(0),
+                eq(false)
+            )
+    }
+
+    @Test
+    fun testSessionPlayer_destroyedWhileActive_noResume_fullyRemoved() {
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
+        addPlaybackStateAction()
+
+        // When a media control using session actions is added, and then the session is destroyed
+        // without timing out first
+        addNotificationAndLoad()
+        val data = mediaDataCaptor.value
+        assertThat(data.active).isTrue()
+        sessionCallbackCaptor.value.invoke(KEY)
+
+        // It is fully removed
+        verify(listener).onMediaDataRemoved(eq(KEY))
+        verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
+        verify(listener, never())
+            .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean())
+    }
+
+    @Test
+    fun testSessionPlayer_canResume_destroyedWhileActive_setToResume() {
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
+        addPlaybackStateAction()
+
+        // When a media control using session actions and that does allow resumption is added,
+        addNotificationAndLoad()
+        val dataResumable = mediaDataCaptor.value.copy(resumeAction = Runnable {})
+        mediaDataManager.onMediaDataLoaded(KEY, null, dataResumable)
+
+        // And then the session is destroyed without timing out first
+        sessionCallbackCaptor.value.invoke(KEY)
+
+        // It is converted to a resume player
+        verify(listener)
+            .onMediaDataLoaded(
+                eq(PACKAGE_NAME),
+                eq(KEY),
+                capture(mediaDataCaptor),
+                eq(true),
+                eq(0),
+                eq(false)
+            )
+        assertThat(mediaDataCaptor.value.resumption).isTrue()
+        assertThat(mediaDataCaptor.value.active).isFalse()
+        verify(logger)
+            .logActiveConvertedToResume(
+                anyInt(),
+                eq(PACKAGE_NAME),
+                eq(mediaDataCaptor.value.instanceId)
+            )
+    }
+
+    @Test
     fun testSessionDestroyed_noNotificationKey_stillRemoved() {
         whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
         whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
index de57b60..5296f1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
@@ -24,7 +24,6 @@
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardViewController
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
 import com.android.systemui.dreams.DreamOverlayStateController
@@ -32,6 +31,7 @@
 import com.android.systemui.media.controls.pipeline.MediaDataManager
 import com.android.systemui.media.dream.MediaDreamComplication
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.SysuiStatusBarStateController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
index 906420d..9630ee3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
@@ -46,6 +46,7 @@
     private val mockContext = mock<Context>()
     private val resources = mock<Resources>()
     private val windowManager = mock<WindowManager>()
+    private val windowMetricsProvider = mock<WindowMetricsProvider>()
     private val sizeUpdates = arrayListOf<Rect>()
     private val testConfigurationController = FakeConfigurationController()
 
@@ -112,13 +113,12 @@
     }
 
     private fun givenTaskbarSize(size: Int) {
-        val windowInsets =
-            WindowInsets.Builder()
-                .setInsets(Type.tappableElement(), Insets.of(Rect(0, 0, 0, size)))
-                .build()
+        val insets = Insets.of(Rect(0, 0, 0, size))
+        val windowInsets = WindowInsets.Builder().setInsets(Type.tappableElement(), insets).build()
         val windowMetrics = WindowMetrics(windowManager.maximumWindowMetrics.bounds, windowInsets)
         whenever(windowManager.maximumWindowMetrics).thenReturn(windowMetrics)
         whenever(windowManager.currentWindowMetrics).thenReturn(windowMetrics)
+        whenever(windowMetricsProvider.currentWindowInsets).thenReturn(insets)
     }
 
     private fun givenDisplay(width: Int, height: Int, isTablet: Boolean = false) {
@@ -126,6 +126,7 @@
         val windowMetrics = WindowMetrics(bounds, { null }, 1.0f)
         whenever(windowManager.maximumWindowMetrics).thenReturn(windowMetrics)
         whenever(windowManager.currentWindowMetrics).thenReturn(windowMetrics)
+        whenever(windowMetricsProvider.maximumWindowBounds).thenReturn(bounds)
 
         val minDimension = min(width, height)
 
@@ -147,7 +148,11 @@
                 }
             }
 
-        return TaskPreviewSizeProvider(mockContext, windowManager, testConfigurationController)
+        return TaskPreviewSizeProvider(
+                mockContext,
+                windowMetricsProvider,
+                testConfigurationController
+            )
             .also { it.addCallback(listener) }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
new file mode 100644
index 0000000..fe18454
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
@@ -0,0 +1,44 @@
+package com.android.systemui.mediaprojection.appselector.view
+
+import android.graphics.Insets
+import android.graphics.Rect
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.core.view.WindowInsetsCompat
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+@SmallTest
+class WindowMetricsProviderImplTest : SysuiTestCase() {
+
+    private val windowManager = mock<WindowManager>()
+    private val windowMetricsProvider = WindowMetricsProviderImpl(windowManager)
+
+    @Test
+    fun getMaximumWindowBounds_returnsValueFromWMMaxWindowMetrics() {
+        val bounds = Rect(/* left= */ 100, /* top= */ 200, /* right= */ 300, /* bottom= */ 400)
+        val metrics =
+            WindowMetrics(bounds, /* windowInsetsSupplier= */ { null }, /* density= */ 1.0f)
+        whenever(windowManager.maximumWindowMetrics).thenReturn(metrics)
+
+        assertThat(windowMetricsProvider.maximumWindowBounds).isEqualTo(bounds)
+    }
+
+    @Test
+    fun getCurrentWindowInsets_returnsFromWMCurrentWindowMetrics() {
+        val bounds = Rect()
+        val insets =
+            Insets.of(Rect(/* left= */ 123, /* top= */ 456, /* right= */ 789, /* bottom= */ 1012))
+        val windowInsets =
+            android.view.WindowInsets.Builder()
+                .setInsets(WindowInsetsCompat.Type.tappableElement(), insets)
+                .build()
+        whenever(windowManager.currentWindowMetrics).thenReturn(WindowMetrics(bounds, windowInsets))
+
+        assertThat(windowMetricsProvider.currentWindowInsets).isEqualTo(insets)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 8019fb5..6248bb1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -57,7 +57,7 @@
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.NotificationChannels;
-import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.FakeGlobalSettings;
 import com.android.systemui.util.settings.GlobalSettings;
 
 import org.junit.Before;
@@ -77,7 +77,7 @@
     public static final String FORMATTED_45M = "0h 45m";
     public static final String FORMATTED_HOUR = "1h 0m";
     private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
-    private final GlobalSettings mGlobalSettings = new FakeSettings();
+    private final GlobalSettings mGlobalSettings = new FakeGlobalSettings();
     private PowerNotificationWarnings mPowerNotificationWarnings;
 
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
index d57765c..c8c134a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs;
 
+import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 
@@ -41,6 +43,7 @@
 import android.os.Bundle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -49,7 +52,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.BouncerPanelExpansionCalculator;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlagsClassic;
@@ -60,6 +62,7 @@
 import com.android.systemui.qs.footer.ui.binder.FooterActionsViewBinder;
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.FakeDisplayTracker;
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.CommandQueue;
@@ -110,6 +113,9 @@
     @Mock private FeatureFlagsClassic mFeatureFlags;
     private View mQsView;
 
+    private final CommandQueue mCommandQueue =
+            new CommandQueue(mContext, new FakeDisplayTracker(mContext));
+
     private QSImpl mUnderTest;
 
 
@@ -120,6 +126,16 @@
         mUnderTest.onComponentCreated(mQsComponent, null);
     }
 
+    /*
+     * Regression test for b/303180152.
+     */
+    @Test
+    public void testDisableCallbackOnDisabledQuickSettingsUponCreationDoesntCrash() {
+        QSImpl other = instantiate();
+        mCommandQueue.disable(Display.DEFAULT_DISPLAY, 0, DISABLE2_QUICK_SETTINGS);
+
+        other.onComponentCreated(mQsComponent, null);
+    }
 
     @Test
     public void testSaveState() {
@@ -473,7 +489,6 @@
 
     private QSImpl instantiate() {
         MockitoAnnotations.initMocks(this);
-        CommandQueue commandQueue = new CommandQueue(mContext, new FakeDisplayTracker(mContext));
 
         setupQsComponent();
         setUpViews();
@@ -484,11 +499,11 @@
         return new QSImpl(
                 new RemoteInputQuickSettingsDisabler(
                         mContext,
-                        commandQueue,
+                        mCommandQueue,
                         new ResourcesSplitShadeStateController(),
                         mock(ConfigurationController.class)),
                 mStatusBarStateController,
-                commandQueue,
+                mCommandQueue,
                 mQSMediaHost,
                 mQQSMediaHost,
                 mBypassController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index e2ac7bc..b825c08 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -42,7 +43,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.logging.testing.UiEventLoggerFake;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.media.controls.ui.MediaHost;
@@ -50,6 +50,7 @@
 import com.android.systemui.qs.customize.QSCustomizerController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.util.animation.DisappearParameters;
 
@@ -341,11 +342,92 @@
     }
 
     @Test
-    public void onViewDetached_removesJustTheAssociatedCallback() {
+    public void onDestroy_removesJustTheAssociatedCallback() {
+        QSPanelControllerBase.TileRecord record = mController.mRecords.get(0);
+
+        mController.destroy();
+        verify(mQSTile).removeCallback(record.callback);
+        verify(mQSTile, never()).removeCallbacks();
+
+        assertThat(mController.mRecords).isEmpty();
+    }
+
+    @Test
+    public void onViewDettached_callbackNotRemoved() {
         QSPanelControllerBase.TileRecord record = mController.mRecords.get(0);
 
         mController.onViewDetached();
-        verify(mQSTile).removeCallback(record.callback);
+        verify(mQSTile, never()).removeCallback(record.callback);
         verify(mQSTile, never()).removeCallbacks();
     }
+
+    @Test
+    public void onInit_qsHostCallbackAdded() {
+        verify(mQSHost).addCallback(any());
+    }
+
+    @Test
+    public void onViewDettached_qsHostCallbackNotRemoved() {
+        mController.onViewDetached();
+        verify(mQSHost, never()).removeCallback(any());
+    }
+
+    @Test
+    public void onDestroy_qsHostCallbackRemoved() {
+        mController.destroy();
+        verify(mQSHost).removeCallback(any());
+    }
+
+    @Test
+    public void setTiles_sameTiles_doesntRemoveAndReaddViews() {
+        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
+        mController.setTiles();
+
+        clearInvocations(mQSPanel);
+
+        mController.setTiles();
+        verify(mQSPanel, never()).removeTile(any());
+        verify(mQSPanel, never()).addTile(any());
+    }
+
+    @Test
+    public void setTiles_differentTiles_allTilesRemovedAndNewTilesAdded() {
+        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
+        mController.setTiles();
+
+        clearInvocations(mQSPanel);
+
+        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile));
+        mController.setTiles();
+
+        verify(mQSPanel, times(2)).removeTile(any());
+        verify(mQSPanel).addTile(any());
+    }
+
+    @Test
+    public void detachAndReattach_sameTiles_doesntRemoveAndReAddViews() {
+        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
+        mController.setTiles();
+
+        clearInvocations(mQSPanel);
+
+        mController.onViewDetached();
+        mController.onViewAttached();
+        verify(mQSPanel, never()).removeTile(any());
+        verify(mQSPanel, never()).addTile(any());
+    }
+
+    @Test
+    public void setTiles_sameTilesDifferentOrder_removesAndReadds() {
+        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
+        mController.setTiles();
+
+        clearInvocations(mQSPanel);
+
+        when(mQSHost.getTiles()).thenReturn(List.of(mOtherTile, mQSTile));
+        mController.setTiles();
+
+        verify(mQSPanel, times(2)).removeTile(any());
+        verify(mQSPanel, times(2)).addTile(any());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/UserSettingObserverTest.kt
similarity index 88%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/qs/UserSettingObserverTest.kt
index 4be6890..8f06fe2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/UserSettingObserverTest.kt
@@ -35,7 +35,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper
-class SettingObserverTest : SysuiTestCase() {
+class UserSettingObserverTest : SysuiTestCase() {
 
     companion object {
         private const val TEST_SETTING = "setting"
@@ -46,7 +46,7 @@
     }
 
     private lateinit var testableLooper: TestableLooper
-    private lateinit var setting: SettingObserver
+    private lateinit var setting: UserSettingObserver
     private lateinit var secureSettings: SecureSettings
 
     private lateinit var callback: Callback
@@ -56,17 +56,19 @@
         testableLooper = TestableLooper.get(this)
         secureSettings = FakeSettings()
 
-        setting = object : SettingObserver(
-                secureSettings,
-                Handler(testableLooper.looper),
-                TEST_SETTING,
-                USER,
-                DEFAULT_VALUE
-        ) {
-            override fun handleValueChanged(value: Int, observedChange: Boolean) {
-                callback(value, observedChange)
+        setting =
+            object :
+                UserSettingObserver(
+                    secureSettings,
+                    Handler(testableLooper.looper),
+                    TEST_SETTING,
+                    USER,
+                    DEFAULT_VALUE
+                ) {
+                override fun handleValueChanged(value: Int, observedChange: Boolean) {
+                    callback(value, observedChange)
+                }
             }
-        }
 
         // Default empty callback
         callback = { _, _ -> Unit }
@@ -162,4 +164,4 @@
         setting.isListening = true
         assertThat(setting.value).isEqualTo(DEFAULT_VALUE)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index 67587e3..6cc52d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -29,12 +29,14 @@
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doAnswer;
 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.when;
 
+import android.app.ActivityManager;
 import android.app.compat.CompatChanges;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -73,16 +75,18 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class TileLifecycleManagerTest extends SysuiTestCase {
-    private static final int TEST_FAIL_TIMEOUT = 5000;
 
     private final PackageManagerAdapter mMockPackageManagerAdapter =
             mock(PackageManagerAdapter.class);
     private final BroadcastDispatcher mMockBroadcastDispatcher =
             mock(BroadcastDispatcher.class);
     private final IQSTileService.Stub mMockTileService = mock(IQSTileService.Stub.class);
+    private final ActivityManager mActivityManager = mock(ActivityManager.class);
+
     private ComponentName mTileServiceComponentName;
     private Intent mTileServiceIntent;
     private UserHandle mUser;
+    private FakeSystemClock mClock;
     private FakeExecutor mExecutor;
     private HandlerThread mThread;
     private Handler mHandler;
@@ -112,13 +116,15 @@
         mThread = new HandlerThread("TestThread");
         mThread.start();
         mHandler = Handler.createAsync(mThread.getLooper());
-        mExecutor = new FakeExecutor(new FakeSystemClock());
+        mClock = new FakeSystemClock();
+        mExecutor = new FakeExecutor(mClock);
         mStateManager = new TileLifecycleManager(mHandler, mWrappedContext,
                 mock(IQSService.class),
                 mMockPackageManagerAdapter,
                 mMockBroadcastDispatcher,
                 mTileServiceIntent,
                 mUser,
+                mActivityManager,
                 mExecutor);
     }
 
@@ -294,11 +300,32 @@
         mStateManager.onStartListening();
         mStateManager.executeSetBindService(true);
         mExecutor.runAllReady();
-        mStateManager.setBindRetryDelay(0);
+        mStateManager.onServiceDisconnected(mTileServiceComponentName);
+        mClock.advanceTime(5000);
+
+        // Two calls: one for the first bind, one for the restart.
+        verifyBind(2);
+        verify(mMockTileService, times(2)).onStartListening();
+    }
+
+    @Test
+    public void testKillProcessLowMemory() throws Exception {
+        doAnswer(invocation -> {
+            ActivityManager.MemoryInfo memoryInfo = invocation.getArgument(0);
+            memoryInfo.lowMemory = true;
+            return null;
+        }).when(mActivityManager).getMemoryInfo(any());
+        mStateManager.onStartListening();
+        mStateManager.executeSetBindService(true);
         mExecutor.runAllReady();
         mStateManager.onServiceDisconnected(mTileServiceComponentName);
-        mExecutor.runAllReady();
 
+        // Longer delay than a regular one
+        mClock.advanceTime(5000);
+        verifyBind(1);
+        verify(mMockTileService, times(1)).onStartListening();
+
+        mClock.advanceTime(20000);
         // Two calls: one for the first bind, one for the restart.
         verifyBind(2);
         verify(mMockTileService, times(2)).onStartListening();
@@ -319,6 +346,7 @@
                 mMockBroadcastDispatcher,
                 mTileServiceIntent,
                 mUser,
+                mActivityManager,
                 mExecutor);
 
         manager.executeSetBindService(true);
@@ -340,6 +368,7 @@
                 mMockBroadcastDispatcher,
                 mTileServiceIntent,
                 mUser,
+                mActivityManager,
                 mExecutor);
 
         manager.executeSetBindService(true);
@@ -361,6 +390,7 @@
                 mMockBroadcastDispatcher,
                 mTileServiceIntent,
                 mUser,
+                mActivityManager,
                 mExecutor);
 
         manager.executeSetBindService(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 4bc16a5..d011821 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -304,7 +304,7 @@
                 CustomTileAddedRepository customTileAddedRepository, DelayableExecutor executor) {
             super(host, handlerProvider, broadcastDispatcher, userTracker, keyguardStateController,
                     commandQueue, statusBarIconController, panelInteractor,
-                    customTileAddedRepository, executor);
+                    mTileLifecycleManagerFactory, customTileAddedRepository, executor);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index 8e8a0c8..9b1f830 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -44,7 +44,7 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.nullable
-import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.FakeGlobalSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.launch
@@ -128,7 +128,7 @@
     fun userSwitcher() = runTest {
         val picture: Drawable = mock()
         val userInfoController = FakeUserInfoController(FakeInfo(picture = picture))
-        val settings = FakeSettings()
+        val settings = FakeGlobalSettings()
         val userId = 42
         val userTracker = FakeUserTracker(userId)
         val userSwitcherControllerWrapper =
@@ -167,14 +167,9 @@
         // for the current user will be fired to notify us of that change.
         isUserSwitcherEnabled = true
 
-        // Update the setting for a random user: nothing should change, given that at this point we
-        // weren't notified of the change yet.
-        utils.setUserSwitcherEnabled(settings, true, 3)
-        assertThat(currentUserSwitcher()).isNull()
-
         // Update the setting for the observed user: now we will be notified and the button should
         // be there.
-        utils.setUserSwitcherEnabled(settings, true, userId)
+        utils.setUserSwitcherEnabled(settings, true)
         val userSwitcher = currentUserSwitcher()
         assertThat(userSwitcher).isNotNull()
         assertThat(userSwitcher!!.icon)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
index 9a55f72..d277fca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
@@ -19,7 +19,6 @@
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -39,7 +38,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class AutoAddSettingsRepositoryTest : SysuiTestCase() {
     private val secureSettings = FakeSettings()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
index 30f5811..3db676d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
@@ -20,7 +20,6 @@
 import android.content.SharedPreferences
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.util.FakeSharedPreferences
@@ -30,7 +29,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CustomTileAddedSharedPreferencesRepositoryTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
index 995de66..070e07a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
@@ -32,7 +32,6 @@
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.util.mockito.any
@@ -62,7 +61,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 @OptIn(ExperimentalCoroutinesApi::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt
index dc09a33..ff8a9bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt
@@ -4,7 +4,6 @@
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.FakeBroadcastDispatcher
 import com.android.systemui.coroutines.collectLastValue
@@ -24,7 +23,6 @@
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
-@RoboPilotTest
 class QSSettingsRestoredBroadcastRepositoryTest : SysuiTestCase() {
     private val dispatcher = StandardTestDispatcher()
     private val testScope = TestScope(dispatcher)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
index 08adebb..f7c3b21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
@@ -20,7 +20,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -40,7 +39,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class TileSpecSettingsRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
index 2087623..9516c21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
@@ -2,14 +2,12 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class TilesSettingConverterTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
index 81fd72b..36e860e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
@@ -3,7 +3,6 @@
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.data.model.RestoreData
@@ -24,7 +23,6 @@
 import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
-@RoboPilotTest
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class UserAutoAddRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
index 389580c1..d4a9fab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
@@ -3,7 +3,6 @@
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.data.model.RestoreData
@@ -23,7 +22,6 @@
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
index 15e401d..4454a3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
@@ -20,7 +20,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.util.mockito.mock
@@ -29,7 +28,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class AutoAddableSettingListTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
index 7c6dd24..d153e9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
@@ -36,7 +35,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class AutoAddableSettingTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
index 469eee3..ec139e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -36,7 +35,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CallbackControllerAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
index b6eaa39..4fae532 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -42,7 +41,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CastAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
index a755fbb..9e2d1f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -41,7 +40,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DataSaverAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
index daacca51..0116bd9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -44,7 +43,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DeviceControlsAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
index 4b5f7f6..e7ea9a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -41,7 +40,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class HotspotAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt
index 32d9db2..20fd360 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt
@@ -19,7 +19,6 @@
 import android.hardware.display.NightDisplayListener
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.NightDisplayListenerModule
@@ -50,7 +49,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class NightDisplayAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
index fb513a6..19ac63c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.ReduceBrightColorsController
@@ -44,7 +43,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
index 5ce15fa..d645ee3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
@@ -21,7 +21,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
@@ -52,7 +51,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class SafetyCenterAutoAddableTest : SysuiTestCase() {
     private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
index 1c8cb54..83ff35d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -38,7 +37,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WalletAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
index de1d29fd..adccc84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
@@ -23,7 +23,6 @@
 import android.content.pm.UserInfo.FLAG_PROFILE
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
@@ -41,7 +40,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WorkTileAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
index bb18115..41a7ec0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dump.DumpManager
@@ -47,7 +46,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class AutoAddInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index a750524..a89338a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -24,7 +24,6 @@
 import android.service.quicksettings.Tile
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dump.nano.SystemUIProtoDump
@@ -71,7 +70,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class CurrentTilesInteractorImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
index 151b256..0d97115 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
@@ -17,7 +17,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.shade.ShadeController
 import org.junit.Before
@@ -27,7 +26,6 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class PanelInteractorImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
index 2e6b50b..f73cab8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
@@ -2,7 +2,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.pipeline.data.model.RestoreData
@@ -20,7 +19,6 @@
 import org.junit.runner.RunWith
 import org.mockito.MockitoAnnotations
 
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class RestoreReconciliationInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
index 34c4c98..558e769 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
@@ -19,14 +19,12 @@
 import android.content.ComponentName
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class TileSpecTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt
index 06b7a9f..5659f01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt
@@ -19,7 +19,6 @@
 import android.content.Intent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.ActivityStarter
 import org.junit.Before
@@ -32,7 +31,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class QSTileIntentUserActionHandlerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
new file mode 100644
index 0000000..9861606
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.analytics
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.InstanceId
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.QSEvent
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class QSTileAnalyticsTest : SysuiTestCase() {
+
+    @Mock private lateinit var uiEventLogger: UiEventLogger
+
+    private lateinit var underTest: QSTileAnalytics
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        underTest = QSTileAnalytics(uiEventLogger)
+    }
+
+    @Test
+    fun testClickIsLogged() {
+        underTest.trackUserAction(config, QSTileUserAction.Click(null))
+
+        verify(uiEventLogger)
+            .logWithInstanceId(
+                eq(QSEvent.QS_ACTION_CLICK),
+                eq(0),
+                eq("test_spec"),
+                eq(InstanceId.fakeInstanceId(0))
+            )
+    }
+
+    @Test
+    fun testLongClickIsLogged() {
+        underTest.trackUserAction(config, QSTileUserAction.LongClick(null))
+
+        verify(uiEventLogger)
+            .logWithInstanceId(
+                eq(QSEvent.QS_ACTION_LONG_PRESS),
+                eq(0),
+                eq("test_spec"),
+                eq(InstanceId.fakeInstanceId(0))
+            )
+    }
+
+    private companion object {
+
+        val config = QSTileConfigTestBuilder.build()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
index 4f25d12..a6199c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
@@ -24,7 +24,6 @@
 import androidx.test.filters.SmallTest
 import com.android.settingslib.RestrictedLockUtils
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.util.mockito.any
@@ -46,7 +45,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DisabledByPolicyInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
new file mode 100644
index 0000000..f1fcee3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.logging
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dump.LogcatEchoTrackerAlways
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.base.interactor.StateUpdateTrigger
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class QSTileLoggerTest : SysuiTestCase() {
+
+    @Mock private lateinit var statusBarController: StatusBarStateController
+
+    private val chattyLogBuffer = LogBuffer("TestChatty", 5, LogcatEchoTrackerAlways())
+    private val logBuffer = LogBuffer("Test", 1, LogcatEchoTrackerAlways())
+
+    private lateinit var underTest: QSTileLogger
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            QSTileLogger(
+                mapOf(TileSpec.create("chatty_tile") to chattyLogBuffer),
+                { logBuffer },
+                statusBarController
+            )
+    }
+
+    @Test
+    fun testChattyLog() {
+        underTest.logUserActionRejectedByFalsing(
+            QSTileUserAction.Click(null),
+            TileSpec.create("chatty_tile"),
+        )
+        underTest.logUserActionRejectedByFalsing(
+            QSTileUserAction.Click(null),
+            TileSpec.create("chatty_tile"),
+        )
+
+        val logs = chattyLogBuffer.getStringBuffer().lines().filter { it.isNotBlank() }
+        assertThat(logs).hasSize(2)
+        logs.forEach { assertThat(it).contains("tile click: rejected by falsing") }
+    }
+
+    @Test
+    fun testLogUserAction() {
+        underTest.logUserAction(
+            QSTileUserAction.Click(null),
+            TileSpec.create("test_spec"),
+            hasData = false,
+            hasTileState = false,
+        )
+
+        assertThat(logBuffer.getStringBuffer())
+            .contains("tile click: statusBarState=SHADE, hasState=false, hasData=false")
+    }
+
+    @Test
+    fun testLogUserActionRejectedByFalsing() {
+        underTest.logUserActionRejectedByFalsing(
+            QSTileUserAction.Click(null),
+            TileSpec.create("test_spec"),
+        )
+
+        assertThat(logBuffer.getStringBuffer()).contains("tile click: rejected by falsing")
+    }
+
+    @Test
+    fun testLogUserActionRejectedByPolicy() {
+        underTest.logUserActionRejectedByPolicy(
+            QSTileUserAction.Click(null),
+            TileSpec.create("test_spec"),
+        )
+
+        assertThat(logBuffer.getStringBuffer()).contains("tile click: rejected by policy")
+    }
+
+    @Test
+    fun testLogUserActionPipeline() {
+        underTest.logUserActionPipeline(
+            TileSpec.create("test_spec"),
+            QSTileUserAction.Click(null),
+            QSTileState.build(Icon.Resource(0, ContentDescription.Resource(0)), "") {},
+            "test_data",
+        )
+
+        assertThat(logBuffer.getStringBuffer())
+            .contains(
+                "tile click pipeline: " +
+                    "statusBarState=SHADE, " +
+                    "state=[" +
+                    "label=, " +
+                    "state=INACTIVE, " +
+                    "s_label=null, " +
+                    "cd=null, " +
+                    "sd=null, " +
+                    "svi=None, " +
+                    "enabled=ENABLED, " +
+                    "a11y=null" +
+                    "], " +
+                    "data=test_data"
+            )
+    }
+
+    @Test
+    fun testLogStateUpdate() {
+        underTest.logStateUpdate(
+            TileSpec.create("test_spec"),
+            StateUpdateTrigger.ForceUpdate,
+            QSTileState.build(Icon.Resource(0, ContentDescription.Resource(0)), "") {},
+            "test_data",
+        )
+
+        assertThat(logBuffer.getStringBuffer())
+            .contains(
+                "tile state update: " +
+                    "trigger=force, " +
+                    "state=[" +
+                    "label=, " +
+                    "state=INACTIVE, " +
+                    "s_label=null, " +
+                    "cd=null, " +
+                    "sd=null, " +
+                    "svi=None, " +
+                    "enabled=ENABLED, " +
+                    "a11y=null" +
+                    "], " +
+                    "data=test_data"
+            )
+    }
+
+    private fun LogBuffer.getStringBuffer(): String {
+        val stringWriter = StringWriter()
+        dump(PrintWriter(stringWriter), 0)
+        return stringWriter.buffer.toString()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
index a0ff2ab..dcda005 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.test.TestCoroutineScheduler
@@ -95,8 +96,7 @@
                 testScope.backgroundScope,
                 dispatcher,
             )
-        `when`(deviceItemInteractor.deviceItemUpdate)
-            .thenReturn(MutableStateFlow(null).asStateFlow())
+        `when`(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow())
         `when`(bluetoothStateInteractor.bluetoothStateUpdate)
             .thenReturn(MutableStateFlow(null).asStateFlow())
         `when`(deviceItemInteractor.deviceItemUpdateRequest)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
index 3593075..428f79c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
@@ -27,10 +27,11 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Rule
@@ -78,7 +79,7 @@
 
     @Before
     fun setUp() {
-        dispatcher = StandardTestDispatcher()
+        dispatcher = UnconfinedTestDispatcher()
         testScope = TestScope(dispatcher)
         interactor =
             DeviceItemInteractor(
@@ -107,9 +108,10 @@
                 listOf(createFactory({ true }, deviceItem1))
             )
 
+            val latest by collectLastValue(interactor.deviceItemUpdate)
             interactor.updateDeviceItems(mContext)
 
-            assertThat(interactor.deviceItemUpdate.value).isEmpty()
+            assertThat(latest).isEqualTo(emptyList<DeviceItem>())
         }
     }
 
@@ -121,9 +123,10 @@
                 listOf(createFactory({ false }, deviceItem1))
             )
 
+            val latest by collectLastValue(interactor.deviceItemUpdate)
             interactor.updateDeviceItems(mContext)
 
-            assertThat(interactor.deviceItemUpdate.value).isEmpty()
+            assertThat(latest).isEqualTo(emptyList<DeviceItem>())
         }
     }
 
@@ -135,10 +138,10 @@
                 listOf(createFactory({ true }, deviceItem1))
             )
 
+            val latest by collectLastValue(interactor.deviceItemUpdate)
             interactor.updateDeviceItems(mContext)
 
-            assertThat(interactor.deviceItemUpdate.value).hasSize(1)
-            assertThat(interactor.deviceItemUpdate.value!![0]).isEqualTo(deviceItem1)
+            assertThat(latest).isEqualTo(listOf(deviceItem1))
         }
     }
 
@@ -150,11 +153,10 @@
                 listOf(createFactory({ false }, deviceItem1), createFactory({ true }, deviceItem2))
             )
 
+            val latest by collectLastValue(interactor.deviceItemUpdate)
             interactor.updateDeviceItems(mContext)
 
-            assertThat(interactor.deviceItemUpdate.value).hasSize(2)
-            assertThat(interactor.deviceItemUpdate.value!![0]).isEqualTo(deviceItem2)
-            assertThat(interactor.deviceItemUpdate.value!![1]).isEqualTo(deviceItem2)
+            assertThat(latest).isEqualTo(listOf(deviceItem2, deviceItem2))
         }
     }
 
@@ -177,10 +179,10 @@
             `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
             `when`(deviceItem2.type).thenReturn(DeviceItemType.SAVED_BLUETOOTH_DEVICE)
 
+            val latest by collectLastValue(interactor.deviceItemUpdate)
             interactor.updateDeviceItems(mContext)
 
-            assertThat(interactor.deviceItemUpdate.value)
-                .isEqualTo(listOf(deviceItem2, deviceItem1))
+            assertThat(latest).isEqualTo(listOf(deviceItem2, deviceItem1))
         }
     }
 
@@ -200,10 +202,10 @@
             `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
             `when`(deviceItem2.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
 
+            val latest by collectLastValue(interactor.deviceItemUpdate)
             interactor.updateDeviceItems(mContext)
 
-            assertThat(interactor.deviceItemUpdate.value)
-                .isEqualTo(listOf(deviceItem2, deviceItem1))
+            assertThat(latest).isEqualTo(listOf(deviceItem2, deviceItem1))
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
index 9024c6c..2084aeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
@@ -1,21 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.systemui.qs.tiles.viewmodel
 
-import android.graphics.drawable.ShapeDrawable
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.android.internal.logging.InstanceId
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
 import com.android.systemui.qs.tiles.base.interactor.FakeDisabledByPolicyInteractor
 import com.android.systemui.qs.tiles.base.interactor.FakeQSTileDataInteractor
 import com.android.systemui.qs.tiles.base.interactor.FakeQSTileUserActionInteractor
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataRequest
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
 import com.android.systemui.qs.tiles.base.interactor.StateUpdateTrigger
+import com.android.systemui.qs.tiles.base.logging.QSTileLogger
 import com.android.systemui.qs.tiles.base.viewmodel.BaseQSTileViewModel
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
@@ -26,17 +43,22 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
 
 // TODO(b/299909368): Add more tests
 @MediumTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class QSTileViewModelInterfaceComplianceTest : SysuiTestCase() {
 
+    @Mock private lateinit var qsTileLogger: QSTileLogger
+    @Mock private lateinit var qsTileAnalytics: QSTileAnalytics
+
     private val fakeQSTileDataInteractor = FakeQSTileDataInteractor<Any>()
     private val fakeQSTileUserActionInteractor = FakeQSTileUserActionInteractor<Any>()
     private val fakeDisabledByPolicyInteractor = FakeDisabledByPolicyInteractor()
+    private val fakeFalsingManager = FalsingManagerFake()
 
     private val testCoroutineDispatcher = StandardTestDispatcher()
     private val testScope = TestScope(testCoroutineDispatcher)
@@ -45,6 +67,7 @@
 
     @Before
     fun setup() {
+        MockitoAnnotations.initMocks(this)
         underTest = createViewModel(testScope)
     }
 
@@ -79,6 +102,9 @@
                     QSTileState.build(Icon.Resource(0, ContentDescription.Resource(0)), "") {}
             },
             fakeDisabledByPolicyInteractor,
+            fakeFalsingManager,
+            qsTileAnalytics,
+            qsTileLogger,
             testCoroutineDispatcher,
             scope.backgroundScope,
         )
@@ -88,7 +114,7 @@
         val TEST_QS_TILE_CONFIG =
             QSTileConfig(
                 TileSpec.create("default"),
-                Icon.Loaded(ShapeDrawable(), null),
+                Icon.Resource(0, null),
                 0,
                 InstanceId.fakeInstanceId(0),
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index f1c99d7..58e36be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -38,11 +39,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class QuickSettingsSceneViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
index 421c355..fe80f70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
@@ -21,7 +21,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.FakeGlobalSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.StandardTestDispatcher
@@ -36,7 +36,7 @@
 @RunWith(AndroidTestingRunner::class)
 class RetailModeSettingsRepositoryTest : SysuiTestCase() {
 
-    private val globalSettings = FakeSettings()
+    private val globalSettings = FakeGlobalSettings()
 
     private val testDispatcher = StandardTestDispatcher()
     private val testScope = TestScope(testDispatcher)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 91f3865..61dd69a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -18,6 +18,7 @@
 
 package com.android.systemui.scene
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
@@ -58,7 +59,6 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 /**
  * Integration test cases for the Scene Framework.
@@ -80,7 +80,7 @@
  */
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class SceneFrameworkIntegrationTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index ff28d2d..432bd0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -18,6 +18,7 @@
 
 package com.android.systemui.scene.data.repository
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -31,10 +32,9 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class SceneContainerRepositoryTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt
index 2187f36..7ae501d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.scene.data.repository
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.SysuiTestCase
@@ -24,9 +25,11 @@
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
+import org.junit.runner.RunWith
 import org.mockito.Mockito.verify
 
 @SmallTest
+@RunWith(AndroidJUnit4::class)
 class WindowRootViewVisibilityRepositoryTest : SysuiTestCase() {
     private val iStatusBarService = mock<IStatusBarService>()
     private val executor = FakeExecutor(FakeSystemClock())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index afc0e69..8b23d18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -14,10 +14,9 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class, ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.scene.domain.interactor
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -26,16 +25,14 @@
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class SceneInteractorTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt
index 3785fd7..8be4eeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.scene.domain.interactor
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.SysuiTestCase
@@ -36,16 +37,16 @@
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
+import org.junit.runner.RunWith
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
 
 @SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
 class WindowRootViewVisibilityInteractorTest : SysuiTestCase() {
 
     private val testScope = TestScope()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 0216a0a..7b13de6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -20,6 +20,7 @@
 
 import android.os.PowerManager
 import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
@@ -46,14 +47,13 @@
 import org.junit.Assume.assumeTrue
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class SceneContainerStartableTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 0b56a59..c89cd9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -18,6 +18,7 @@
 
 package com.android.systemui.scene.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -29,10 +30,9 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class SceneContainerViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
index 1bb2ff8..263b001 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
@@ -42,6 +42,7 @@
         @Parameterized.Parameters
         fun data(): Iterable<String> =
             listOf(
+                Intent.ACTION_LOCALE_CHANGED,
                 Intent.ACTION_USER_INFO_CHANGED,
                 Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
                 Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index 52b25f8..c32d259 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -177,7 +177,8 @@
         verify(context)
                 .registerReceiverForAllUsers(eq(tracker), capture(captor), isNull(), eq(handler))
         with(captor.value) {
-            assertThat(countActions()).isEqualTo(6)
+            assertThat(countActions()).isEqualTo(7)
+            assertThat(hasAction(Intent.ACTION_LOCALE_CHANGED)).isTrue()
             assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue()
             assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue()
             assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 7b12931..8d8c70e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -79,7 +79,6 @@
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
 import com.android.keyguard.logging.KeyguardLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
@@ -120,6 +119,7 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.qs.QSFragmentLegacy;
+import com.android.systemui.res.R;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.data.repository.ShadeRepository;
@@ -153,7 +153,6 @@
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
@@ -170,6 +169,7 @@
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
@@ -182,6 +182,8 @@
 import com.android.systemui.util.time.SystemClock;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
+import dagger.Lazy;
+
 import org.junit.After;
 import org.junit.Before;
 import org.mockito.ArgumentCaptor;
@@ -193,7 +195,6 @@
 import java.util.List;
 import java.util.Optional;
 
-import dagger.Lazy;
 import kotlinx.coroutines.CoroutineDispatcher;
 
 public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
@@ -208,7 +209,7 @@
     @Mock protected KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
     @Mock protected ViewPropertyAnimator mViewPropertyAnimator;
     @Mock protected KeyguardBottomAreaView mQsFrame;
-    @Mock protected HeadsUpManagerPhone mHeadsUpManager;
+    @Mock protected HeadsUpManager mHeadsUpManager;
     @Mock protected NotificationShelfController mNotificationShelfController;
     @Mock protected NotificationGutsManager mGutsManager;
     @Mock protected KeyguardStatusBarView mKeyguardStatusBar;
@@ -527,7 +528,7 @@
         NotificationWakeUpCoordinator coordinator =
                 new NotificationWakeUpCoordinator(
                         mDumpManager,
-                        mock(HeadsUpManagerPhone.class),
+                        mock(HeadsUpManager.class),
                         new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager,
                                 mInteractionJankMonitor, mShadeExpansionStateManager),
                         mKeyguardBypassController,
@@ -547,7 +548,7 @@
                 mLockscreenShadeTransitionController,
                 new FalsingCollectorFake(),
                 mDumpManager);
-        when(mKeyguardStatusViewComponentFactory.build(any()))
+        when(mKeyguardStatusViewComponentFactory.build(any(), any()))
                 .thenReturn(mKeyguardStatusViewComponent);
         when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
                 .thenReturn(mKeyguardClockSwitchController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 2ed2090..eb00610 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -47,18 +47,34 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.keyguard.KeyguardSecurityModel;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.data.repository.FakePowerRepository;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.FakeWindowRootViewComponent;
 import com.android.systemui.scene.SceneTestUtils;
+import com.android.systemui.scene.data.repository.SceneContainerRepository;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
+import com.android.systemui.scene.shared.logger.SceneLogger;
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.StatusBarState;
@@ -71,9 +87,9 @@
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
 import com.android.systemui.user.domain.interactor.UserInteractor;
 
 import com.google.common.util.concurrent.MoreExecutors;
@@ -109,6 +125,7 @@
     @Mock private SysuiColorExtractor mColorExtractor;
     @Mock ColorExtractor.GradientColors mGradientColors;
     @Mock private DumpManager mDumpManager;
+    @Mock private KeyguardSecurityModel mKeyguardSecurityModel;
     @Mock private KeyguardStateController mKeyguardStateController;
     @Mock private ScreenOffAnimationController mScreenOffAnimationController;
     @Mock private AuthController mAuthController;
@@ -123,6 +140,8 @@
 
     private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
     private float mPreferredRefreshRate = -1;
+    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor;
+    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;
 
     @Before
     public void setUp() {
@@ -137,22 +156,86 @@
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
+        FakeKeyguardRepository keyguardRepository = new FakeKeyguardRepository();
+        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic();
+        FakeShadeRepository shadeRepository = new FakeShadeRepository();
+        FakePowerRepository powerRepository = new FakePowerRepository();
+
+        PowerInteractor powerInteractor = new PowerInteractor(
+                powerRepository,
+                new FalsingCollectorFake(),
+                mScreenOffAnimationController,
+                mStatusBarStateController);
+
+        SceneInteractor sceneInteractor = new SceneInteractor(
+                mTestScope.getBackgroundScope(),
+                new SceneContainerRepository(
+                        mTestScope.getBackgroundScope(),
+                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+                powerRepository,
+                mock(SceneLogger.class));
+
+        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository();
+        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
+                keyguardRepository,
+                new FakeCommandQueue(),
+                powerInteractor,
+                featureFlags,
+                sceneContainerFlags,
+                new FakeDeviceEntryRepository(),
+                new FakeKeyguardBouncerRepository(),
+                configurationRepository,
+                shadeRepository,
+                () -> sceneInteractor);
+
+        FakeKeyguardTransitionRepository keyguardTransitionRepository =
+                new FakeKeyguardTransitionRepository();
+
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                new KeyguardTransitionInteractor(
+                        mTestScope.getBackgroundScope(),
+                        keyguardTransitionRepository,
+                        () -> keyguardInteractor,
+                        () -> mFromLockscreenTransitionInteractor,
+                        () -> mFromPrimaryBouncerTransitionInteractor);
+
+        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                shadeRepository,
+                powerInteractor);
+
+        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                mKeyguardSecurityModel,
+                powerInteractor);
+
         mShadeInteractor =
                 new ShadeInteractor(
                         mTestScope.getBackgroundScope(),
+                        new FakeDeviceProvisioningRepository(),
                         new FakeDisableFlagsRepository(),
-                        new FakeSceneContainerFlags(),
-                        mUtils::sceneInteractor,
-                        new FakeKeyguardRepository(),
+                        mock(DozeParameters.class),
+                        sceneContainerFlags,
+                        () -> sceneInteractor,
+                        keyguardRepository,
+                        keyguardTransitionInteractor,
+                        powerInteractor,
                         new FakeUserSetupRepository(),
-                        mock(DeviceProvisionedController.class),
                         mock(UserInteractor.class),
                         new SharedNotificationContainerInteractor(
-                                new FakeConfigurationRepository(),
+                                configurationRepository,
                                 mContext,
                                 new ResourcesSplitShadeStateController()),
-                        new FakeShadeRepository()
-                );
+                        shadeRepository);
 
         mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(
                 mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 9651072..677d9db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
 import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
 import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -48,7 +49,7 @@
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.SystemPropertiesHelper
-import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
+import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
@@ -83,7 +84,6 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
-import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.test.TestScope
@@ -97,8 +97,9 @@
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
+import java.util.Optional
+import org.mockito.Mockito.`when` as whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -143,7 +144,9 @@
     @Mock lateinit var dragDownHelper: DragDownHelper
     @Mock
     lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
-    @Mock lateinit var keyEventInteractor: KeyEventInteractor
+    @Mock lateinit var sysUIKeyEventHandler: SysUIKeyEventHandler
+    @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+    @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
     private val notificationExpansionRepository = NotificationExpansionRepository()
 
     private lateinit var fakeClock: FakeSystemClock
@@ -176,6 +179,7 @@
         featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
         featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
         featureFlags.set(Flags.MIGRATE_NSSL, false)
+        featureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false)
 
         testScope = TestScope()
         fakeClock = FakeSystemClock()
@@ -247,7 +251,9 @@
                     securityModel = mock(KeyguardSecurityModel::class.java),
                 ),
                 BouncerLogger(logcatLogBuffer("BouncerLog")),
-                keyEventInteractor,
+                sysUIKeyEventHandler,
+                primaryBouncerInteractor,
+                alternateBouncerInteractor,
             )
         underTest.setupExpandedStatusBar()
         underTest.setDragDownHelper(dragDownHelper)
@@ -425,29 +431,37 @@
     }
 
     @Test
-    fun shouldInterceptTouchEvent_notificationPanelViewControllerShouldIntercept() {
-        // GIVEN not dozing
-        whenever(sysuiStatusBarStateController.isDozing()).thenReturn(false)
+    fun shouldInterceptTouchEvent_dozing_touchInLockIconArea_touchNotIntercepted() {
+        // GIVEN dozing
+        whenever(sysuiStatusBarStateController.isDozing).thenReturn(true)
         // AND alternate bouncer doesn't want the touch
         whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
             .thenReturn(false)
-        // AND the lock icon doesn't want the touch
-        whenever(lockIconViewController.onInterceptTouchEvent(DOWN_EVENT)).thenReturn(false)
-        // AND the notification panel can accept touches
-        whenever(notificationPanelViewController.isFullyExpanded()).thenReturn(true)
-        whenever(dragDownHelper.isDragDownEnabled).thenReturn(true)
-        whenever(centralSurfaces.isBouncerShowing()).thenReturn(false)
-
-        // AND the drag down helper doesn't want the touch (to pull the shade down)
-        whenever(dragDownHelper.onInterceptTouchEvent(DOWN_EVENT)).thenReturn(false)
+        // AND the lock icon wants the touch
+        whenever(lockIconViewController.willHandleTouchWhileDozing(DOWN_EVENT))
+                .thenReturn(true)
 
         featureFlags.set(Flags.MIGRATE_NSSL, true)
 
-        // WHEN asked if should intercept touch
-        interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)
+        // THEN touch should NOT be intercepted by NotificationShade
+        assertThat(interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)).isFalse()
+    }
 
-        // Verify that NPVC gets a chance to use the touch
-        verify(notificationPanelViewController).handleExternalInterceptTouch(DOWN_EVENT)
+    @Test
+    fun shouldInterceptTouchEvent_dozing_touchNotInLockIconArea_touchIntercepted() {
+        // GIVEN dozing
+        whenever(sysuiStatusBarStateController.isDozing).thenReturn(true)
+        // AND alternate bouncer doesn't want the touch
+        whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
+                .thenReturn(false)
+        // AND the lock icon does NOT want the touch
+        whenever(lockIconViewController.willHandleTouchWhileDozing(DOWN_EVENT))
+                .thenReturn(false)
+
+        featureFlags.set(Flags.MIGRATE_NSSL, true)
+
+        // THEN touch should NOT be intercepted by NotificationShade
+        assertThat(interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)).isTrue()
     }
 
     @Test
@@ -461,21 +475,21 @@
     fun forwardsDispatchKeyEvent() {
         val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
         interactionEventHandler.dispatchKeyEvent(keyEvent)
-        verify(keyEventInteractor).dispatchKeyEvent(keyEvent)
+        verify(sysUIKeyEventHandler).dispatchKeyEvent(keyEvent)
     }
 
     @Test
     fun forwardsDispatchKeyEventPreIme() {
         val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
         interactionEventHandler.dispatchKeyEventPreIme(keyEvent)
-        verify(keyEventInteractor).dispatchKeyEventPreIme(keyEvent)
+        verify(sysUIKeyEventHandler).dispatchKeyEventPreIme(keyEvent)
     }
 
     @Test
     fun forwardsInterceptMediaKey() {
         val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
         interactionEventHandler.interceptMediaKey(keyEvent)
-        verify(keyEventInteractor).interceptMediaKey(keyEvent)
+        verify(sysUIKeyEventHandler).interceptMediaKey(keyEvent)
     }
 
     companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 0023020..a4a2ca0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
 import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
 import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -47,7 +48,7 @@
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.SystemPropertiesHelper
-import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
+import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
@@ -141,6 +142,8 @@
         Optional<UnfoldTransitionProgressProvider>
     @Mock private lateinit var notificationInsetsController: NotificationInsetsController
     @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+    @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+    @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
     @Mock
     private lateinit var primaryBouncerToGoneTransitionViewModel:
         PrimaryBouncerToGoneTransitionViewModel
@@ -180,6 +183,7 @@
         featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
         featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
         featureFlags.set(Flags.MIGRATE_NSSL, false)
+        featureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false)
         testScope = TestScope()
         controller =
             NotificationShadeWindowViewController(
@@ -249,7 +253,9 @@
                     securityModel = Mockito.mock(KeyguardSecurityModel::class.java),
                 ),
                 BouncerLogger(logcatLogBuffer("BouncerLog")),
-                Mockito.mock(KeyEventInteractor::class.java),
+                Mockito.mock(SysUIKeyEventHandler::class.java),
+                primaryBouncerInteractor,
+                alternateBouncerInteractor,
             )
 
         controller.setupExpandedStatusBar()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index 8138b32..65174ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -32,23 +32,39 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
+import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.media.controls.pipeline.MediaDataManager;
 import com.android.systemui.media.controls.ui.MediaHierarchyManager;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.power.data.repository.FakePowerRepository;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.qs.QSFragmentLegacy;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.SceneTestUtils;
+import com.android.systemui.scene.data.repository.SceneContainerRepository;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
+import com.android.systemui.scene.shared.logger.SceneLogger;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
@@ -64,19 +80,21 @@
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
 import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
 import com.android.systemui.user.domain.interactor.UserInteractor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
@@ -103,8 +121,7 @@
     protected SceneTestUtils mUtils = new SceneTestUtils(this);
     protected TestScope mTestScope = mUtils.getTestScope();
 
-    @Mock
-    protected Resources mResources;
+    @Mock protected Resources mResources;
     @Mock protected KeyguardBottomAreaView mQsFrame;
     @Mock protected KeyguardStatusBarView mKeyguardStatusBar;
     @Mock protected QS mQs;
@@ -126,6 +143,7 @@
     @Mock protected NotificationShadeDepthController mNotificationShadeDepthController;
     @Mock protected ShadeHeaderController mShadeHeaderController;
     @Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    @Mock protected DozeParameters mDozeParameters;
     @Mock protected KeyguardStateController mKeyguardStateController;
     @Mock protected KeyguardBypassController mKeyguardBypassController;
     @Mock protected KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -144,7 +162,6 @@
     @Mock protected DumpManager mDumpManager;
     @Mock protected UiEventLogger mUiEventLogger;
     @Mock protected CastController mCastController;
-    @Mock protected DeviceProvisionedController mDeviceProvisionedController;
     @Mock protected UserInteractor mUserInteractor;
     protected FakeDisableFlagsRepository mDisableFlagsRepository =
             new FakeDisableFlagsRepository();
@@ -161,6 +178,8 @@
             new ShadeExpansionStateManager();
 
     protected FragmentHostManager.FragmentListener mFragmentListener;
+    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor;
+    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;
 
     @Before
     public void setup() {
@@ -169,21 +188,89 @@
         mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
                 mInteractionJankMonitor, mShadeExpansionStateManager);
 
-        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+        FakeDeviceProvisioningRepository deviceProvisioningRepository =
+                new FakeDeviceProvisioningRepository();
+        deviceProvisioningRepository.setDeviceProvisioned(true);
+        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic();
+        FakePowerRepository powerRepository = new FakePowerRepository();
+        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository();
+
+        PowerInteractor powerInteractor = new PowerInteractor(
+                powerRepository,
+                new FalsingCollectorFake(),
+                mock(ScreenOffAnimationController.class),
+                mStatusBarStateController);
+
+        SceneInteractor sceneInteractor = new SceneInteractor(
+                mTestScope.getBackgroundScope(),
+                new SceneContainerRepository(
+                        mTestScope.getBackgroundScope(),
+                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+                powerRepository,
+                mock(SceneLogger.class));
+
+        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
+                mKeyguardRepository,
+                new FakeCommandQueue(),
+                powerInteractor,
+                featureFlags,
+                sceneContainerFlags,
+                new FakeDeviceEntryRepository(),
+                new FakeKeyguardBouncerRepository(),
+                configurationRepository,
+                mShadeRepository,
+                () -> sceneInteractor);
+
+        FakeKeyguardTransitionRepository keyguardTransitionRepository =
+                new FakeKeyguardTransitionRepository();
+
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                new KeyguardTransitionInteractor(
+                        mTestScope.getBackgroundScope(),
+                        keyguardTransitionRepository,
+                        () -> keyguardInteractor,
+                        () -> mFromLockscreenTransitionInteractor,
+                        () -> mFromPrimaryBouncerTransitionInteractor);
+
+        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                mShadeRepository,
+                powerInteractor);
+
+        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                mock(KeyguardSecurityModel.class),
+                powerInteractor);
+
+        ResourcesSplitShadeStateController splitShadeStateController =
+                new ResourcesSplitShadeStateController();
+
         mShadeInteractor =
                 new ShadeInteractor(
                         mTestScope.getBackgroundScope(),
+                        deviceProvisioningRepository,
                         mDisableFlagsRepository,
-                        new FakeSceneContainerFlags(),
-                        () -> mUtils.sceneInteractor(),
+                        mDozeParameters,
+                        sceneContainerFlags,
+                        () -> sceneInteractor,
                         mKeyguardRepository,
+                        keyguardTransitionInteractor,
+                        powerInteractor,
                         new FakeUserSetupRepository(),
-                        mDeviceProvisionedController,
                         mUserInteractor,
                         new SharedNotificationContainerInteractor(
-                                new FakeConfigurationRepository(),
+                                configurationRepository,
                                 mContext,
-                                new ResourcesSplitShadeStateController()),
+                                splitShadeStateController),
                         mShadeRepository
                 );
 
@@ -262,7 +349,7 @@
                 mShadeInteractor,
                 new JavaAdapter(mTestScope.getBackgroundScope()),
                 mCastController,
-                new ResourcesSplitShadeStateController()
+                splitShadeStateController
         );
         mQsController.init();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index b5841a9..215f8b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.shade
 
 import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
 import android.view.Display
 import android.view.WindowManager
 import androidx.test.filters.SmallTest
@@ -54,6 +55,7 @@
 import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class ShadeControllerImplTest : SysuiTestCase() {
     private val executor = FakeExecutor(FakeSystemClock())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index 2be1c09..81382a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -16,50 +16,52 @@
 
 package com.android.systemui.shade.data.repository
 
-import android.app.ActivityManager
 import android.app.StatusBarManager.DISABLE2_NONE
 import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
 import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
 import android.content.pm.UserInfo
 import android.os.UserManager
 import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
-import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.SysUITestModule
+import com.android.TestMocksModule
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
 import com.android.systemui.res.R
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
-import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
-import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
 import com.android.systemui.user.data.model.UserSwitcherSettingsModel
 import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.interactor.GuestUserInteractor
-import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
-import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
-import com.android.systemui.user.domain.interactor.UserInteractor
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.user.domain.UserDomainLayerModule
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -70,50 +72,55 @@
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
 class ShadeInteractorTest : SysuiTestCase() {
+
+    @Mock private lateinit var dozeParameters: DozeParameters
+
+    private lateinit var testComponent: TestComponent
+
+    private val configurationRepository
+        get() = testComponent.configurationRepository
+    private val deviceProvisioningRepository
+        get() = testComponent.deviceProvisioningRepository
+    private val disableFlagsRepository
+        get() = testComponent.disableFlagsRepository
+    private val keyguardRepository
+        get() = testComponent.keyguardRepository
+    private val keyguardTransitionRepository
+        get() = testComponent.keygaurdTransitionRepository
+    private val powerRepository
+        get() = testComponent.powerRepository
+    private val sceneInteractor
+        get() = testComponent.sceneInteractor
+    private val shadeRepository
+        get() = testComponent.shadeRepository
+    private val testScope
+        get() = testComponent.testScope
+    private val userRepository
+        get() = testComponent.userRepository
+    private val userSetupRepository
+        get() = testComponent.userSetupRepository
+
     private lateinit var underTest: ShadeInteractor
 
-    private val utils = SceneTestUtils(this)
-    private val testScope = utils.testScope
-    private val featureFlags = FakeFeatureFlags()
-    private val sceneContainerFlags = FakeSceneContainerFlags()
-    private val sceneInteractor = utils.sceneInteractor()
-    private val userSetupRepository = FakeUserSetupRepository()
-    private val userRepository = FakeUserRepository()
-    private val disableFlagsRepository = FakeDisableFlagsRepository()
-    private val keyguardRepository = FakeKeyguardRepository()
-    private val shadeRepository = FakeShadeRepository()
-    private val configurationRepository = FakeConfigurationRepository()
-    private val sharedNotificationContainerInteractor =
-        SharedNotificationContainerInteractor(
-            configurationRepository,
-            mContext,
-            ResourcesSplitShadeStateController()
-        )
-
-    @Mock private lateinit var manager: UserManager
-    @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
-    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
-    @Mock private lateinit var activityStarter: ActivityStarter
-    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
-    @Mock private lateinit var activityManager: ActivityManager
-    @Mock private lateinit var uiEventLogger: UiEventLogger
-    @Mock private lateinit var guestInteractor: GuestUserInteractor
-
-    private lateinit var userInteractor: UserInteractor
-
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        featureFlags.set(Flags.FACE_AUTH_REFACTOR, false)
-        featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
-
-        val refreshUsersScheduler =
-            RefreshUsersScheduler(
-                applicationScope = testScope.backgroundScope,
-                mainDispatcher = utils.testDispatcher,
-                repository = userRepository,
-            )
+        testComponent =
+            DaggerShadeInteractorTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FACE_AUTH_REFACTOR, false)
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            dozeParameters = dozeParameters,
+                        ),
+                )
+        underTest = testComponent.underTest
 
         runBlocking {
             val userInfos =
@@ -131,44 +138,6 @@
             userRepository.setUserInfos(userInfos)
             userRepository.setSelectedUserInfo(userInfos[0])
         }
-        userInteractor =
-            UserInteractor(
-                applicationContext = context,
-                repository = userRepository,
-                activityStarter = activityStarter,
-                keyguardInteractor =
-                    KeyguardInteractorFactory.create(featureFlags = featureFlags)
-                        .keyguardInteractor,
-                featureFlags = featureFlags,
-                manager = manager,
-                headlessSystemUserMode = headlessSystemUserMode,
-                applicationScope = testScope.backgroundScope,
-                telephonyInteractor =
-                    TelephonyInteractor(
-                        repository = FakeTelephonyRepository(),
-                    ),
-                broadcastDispatcher = fakeBroadcastDispatcher,
-                keyguardUpdateMonitor = keyguardUpdateMonitor,
-                backgroundDispatcher = utils.testDispatcher,
-                activityManager = activityManager,
-                refreshUsersScheduler = refreshUsersScheduler,
-                guestUserInteractor = guestInteractor,
-                uiEventLogger = uiEventLogger,
-                userRestrictionChecker = mock(),
-            )
-        underTest =
-            ShadeInteractor(
-                testScope.backgroundScope,
-                disableFlagsRepository,
-                sceneContainerFlags,
-                { sceneInteractor },
-                keyguardRepository,
-                userSetupRepository,
-                deviceProvisionedController,
-                userInteractor,
-                sharedNotificationContainerInteractor,
-                shadeRepository,
-            )
     }
 
     @Test
@@ -188,7 +157,7 @@
     @Test
     fun isExpandToQsEnabled_deviceNotProvisioned_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
+            deviceProvisioningRepository.setDeviceProvisioned(false)
 
             val actual by collectLastValue(underTest.isExpandToQsEnabled)
 
@@ -198,7 +167,7 @@
     @Test
     fun isExpandToQsEnabled_userNotSetupAndSimpleUserSwitcher_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
 
             userSetupRepository.setUserSetup(false)
             userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true))
@@ -211,7 +180,7 @@
     @Test
     fun isExpandToQsEnabled_shadeNotEnabled_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
 
             disableFlagsRepository.disableFlags.value =
@@ -227,7 +196,7 @@
     @Test
     fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
 
             disableFlagsRepository.disableFlags.value =
@@ -242,7 +211,7 @@
     @Test
     fun isExpandToQsEnabled_dozing_false() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -259,7 +228,7 @@
     @Test
     fun isExpandToQsEnabled_userSetup_true() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -276,7 +245,7 @@
     @Test
     fun isExpandToQsEnabled_notSimpleUserSwitcher_true() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -293,7 +262,7 @@
     @Test
     fun isExpandToQsEnabled_respondsToDozingUpdates() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -321,7 +290,7 @@
     @Test
     fun isExpandToQsEnabled_respondsToDisableUpdates() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -353,7 +322,7 @@
     @Test
     fun isExpandToQsEnabled_respondsToUserUpdates() =
         testScope.runTest {
-            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+            deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
@@ -1129,4 +1098,168 @@
             // THEN interacting is false
             assertThat(interacting).isFalse()
         }
+
+    @Test
+    fun isShadeTouchable_isFalse_whenFrpIsActive() =
+        testScope.runTest {
+            deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isFalse()
+        }
+
+    @Test
+    fun isShadeTouchable_isFalse_whenDeviceAsleepAndNotPulsing() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            // goingToSleep == false
+            // TODO: remove?
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.LOCKSCREEN,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_AOD,
+                )
+            )
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isFalse()
+        }
+
+    @Test
+    fun isShadeTouchable_isTrue_whenDeviceAsleepAndPulsing() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            // goingToSleep == false
+            // TODO: remove?
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.LOCKSCREEN,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_PULSING,
+                )
+            )
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isTrue()
+        }
+
+    @Test
+    fun isShadeTouchable_isFalse_whenStartingToSleepAndNotControlScreenOff() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            // goingToSleep == true
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(false)
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isFalse()
+        }
+
+    @Test
+    fun isShadeTouchable_isTrue_whenStartingToSleepAndControlScreenOff() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            // goingToSleep == true
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(true)
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isTrue()
+        }
+
+    @Test
+    fun isShadeTouchable_isTrue_whenNotAsleep() =
+        testScope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
+            runCurrent()
+            assertThat(isShadeTouchable).isTrue()
+        }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: ShadeInteractor
+
+        val configurationRepository: FakeConfigurationRepository
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val disableFlagsRepository: FakeDisableFlagsRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keygaurdTransitionRepository: FakeKeyguardTransitionRepository
+        val powerRepository: FakePowerRepository
+        val sceneInteractor: SceneInteractor
+        val shadeRepository: FakeShadeRepository
+        val testScope: TestScope
+        val userRepository: FakeUserRepository
+        val userSetupRepository: FakeUserSetupRepository
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index 7463e65..6eeafefd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionStateManager
@@ -43,7 +42,6 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class ShadeRepositoryImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index 0925858..607cdab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.shade.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -20,11 +21,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class ShadeHeaderViewModelTest : SysuiTestCase() {
     private val utils = SceneTestUtils(this)
     private val testScope = utils.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 602bd5f..c423782 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shade.ui.viewmodel
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.model.AuthenticationMethodModel
@@ -37,11 +38,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class ShadeSceneViewModelTest : SysuiTestCase() {
 
     private val utils = SceneTestUtils(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index e714736..ae659f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -131,11 +131,10 @@
 
         fun addClock(
             id: ClockId,
-            name: String,
             create: (ClockId) -> ClockController = ::failFactory,
             getThumbnail: (ClockId) -> Drawable? = ::failThumbnail
         ): FakeClockPlugin {
-            metadata.add(ClockMetadata(id, name))
+            metadata.add(ClockMetadata(id))
             createCallbacks[id] = create
             thumbnailCallbacks[id] = getThumbnail
             return this
@@ -149,7 +148,7 @@
         scope = TestScope(dispatcher)
 
         fakeDefaultProvider = FakeClockPlugin()
-            .addClock(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME, { mockDefaultClock }, { mockThumbnail })
+            .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { mockThumbnail })
         whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
 
         val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>()
@@ -183,13 +182,13 @@
     @Test
     fun pluginRegistration_CorrectState() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = FakeLifecycle("1", plugin1)
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3")
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3")
+            .addClock("clock_4")
         val lifecycle2 = FakeLifecycle("2", plugin2)
 
         pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
@@ -198,11 +197,11 @@
         assertEquals(
             list.toSet(),
             setOf(
-                ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
-                ClockMetadata("clock_1", "clock 1"),
-                ClockMetadata("clock_2", "clock 2"),
-                ClockMetadata("clock_3", "clock 3"),
-                ClockMetadata("clock_4", "clock 4")
+                ClockMetadata(DEFAULT_CLOCK_ID),
+                ClockMetadata("clock_1"),
+                ClockMetadata("clock_2"),
+                ClockMetadata("clock_3"),
+                ClockMetadata("clock_4")
             )
         )
     }
@@ -216,13 +215,13 @@
     @Test
     fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail })
-            .addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail })
+            .addClock("clock_1", { mockClock }, { mockThumbnail })
+            .addClock("clock_2", { mockClock }, { mockThumbnail })
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
@@ -231,9 +230,9 @@
         assertEquals(
             list.toSet(),
             setOf(
-                ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
-                ClockMetadata("clock_1", "clock 1"),
-                ClockMetadata("clock_2", "clock 2")
+                ClockMetadata(DEFAULT_CLOCK_ID),
+                ClockMetadata("clock_1"),
+                ClockMetadata("clock_2")
             )
         )
 
@@ -248,13 +247,13 @@
     @Test
     fun createCurrentClock_pluginConnected() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3", { mockClock })
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3", { mockClock })
+            .addClock("clock_4")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
@@ -268,13 +267,13 @@
     @Test
     fun activeClockId_changeAfterPluginConnected() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3", { mockClock })
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3", { mockClock })
+            .addClock("clock_4")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
@@ -289,13 +288,13 @@
     @Test
     fun createDefaultClock_pluginDisconnected() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3")
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3")
+            .addClock("clock_4")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
@@ -310,13 +309,13 @@
     @Test
     fun pluginRemoved_clockAndListChanged() {
         val plugin1 = FakeClockPlugin()
-            .addClock("clock_1", "clock 1")
-            .addClock("clock_2", "clock 2")
+            .addClock("clock_1")
+            .addClock("clock_2")
         val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
-            .addClock("clock_3", "clock 3", { mockClock })
-            .addClock("clock_4", "clock 4")
+            .addClock("clock_3", { mockClock })
+            .addClock("clock_4")
         val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         var changeCallCount = 0
@@ -415,13 +414,13 @@
 
     @Test
     fun pluginAddRemove_concurrentModification() {
-        val plugin1 = FakeClockPlugin().addClock("clock_1", "clock 1")
+        val plugin1 = FakeClockPlugin().addClock("clock_1")
         val lifecycle1 = FakeLifecycle("1", plugin1)
-        val plugin2 = FakeClockPlugin().addClock("clock_2", "clock 2")
+        val plugin2 = FakeClockPlugin().addClock("clock_2")
         val lifecycle2 = FakeLifecycle("2", plugin2)
-        val plugin3 = FakeClockPlugin().addClock("clock_3", "clock 3")
+        val plugin3 = FakeClockPlugin().addClock("clock_3")
         val lifecycle3 = FakeLifecycle("3", plugin3)
-        val plugin4 = FakeClockPlugin().addClock("clock_4", "clock 4")
+        val plugin4 = FakeClockPlugin().addClock("clock_4")
         val lifecycle4 = FakeLifecycle("4", plugin4)
 
         // Set the current clock to the final clock to load
@@ -450,10 +449,10 @@
 
         // Verify all plugins were correctly loaded into the registry
         assertEquals(registry.getClocks().toSet(), setOf(
-            ClockMetadata("DEFAULT", "Default Clock"),
-            ClockMetadata("clock_2", "clock 2"),
-            ClockMetadata("clock_3", "clock 3"),
-            ClockMetadata("clock_4", "clock 4")
+            ClockMetadata("DEFAULT"),
+            ClockMetadata("clock_2"),
+            ClockMetadata("clock_3"),
+            ClockMetadata("clock_4")
         ))
     }
 
@@ -527,8 +526,8 @@
         featureFlags.set(TRANSIT_CLOCK, flag)
         registry.isTransitClockEnabled = featureFlags.isEnabled(TRANSIT_CLOCK)
         val plugin = FakeClockPlugin()
-                .addClock("clock_1", "clock 1")
-                .addClock("DIGITAL_CLOCK_METRO", "metro clock")
+                .addClock("clock_1")
+                .addClock("DIGITAL_CLOCK_METRO")
         val lifecycle = FakeLifecycle("metro", plugin)
         pluginListener.onPluginLoaded(plugin, mockContext, lifecycle)
 
@@ -536,17 +535,17 @@
         if (flag) {
             assertEquals(
                     setOf(
-                            ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
-                            ClockMetadata("clock_1", "clock 1"),
-                            ClockMetadata("DIGITAL_CLOCK_METRO", "metro clock")
+                            ClockMetadata(DEFAULT_CLOCK_ID),
+                            ClockMetadata("clock_1"),
+                            ClockMetadata("DIGITAL_CLOCK_METRO")
                     ),
                     list.toSet()
             )
         } else {
             assertEquals(
                     setOf(
-                            ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
-                            ClockMetadata("clock_1", "clock 1")
+                            ClockMetadata(DEFAULT_CLOCK_ID),
+                            ClockMetadata("clock_1")
                     ),
                     list.toSet()
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt
index 7a2d122..b8fe2f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -33,7 +32,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class BcSmartspaceConfigProviderTest : SysuiTestCase() {
     @Mock private lateinit var featureFlags: FeatureFlags
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
index f1c181f..e093859 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
@@ -26,7 +26,6 @@
 import android.widget.FrameLayout
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dreams.smartspace.DreamSmartspaceController
 import com.android.systemui.plugins.BcSmartspaceConfigPlugin
@@ -53,7 +52,6 @@
 import org.mockito.Spy
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class DreamSmartspaceControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
index 7af29ba..886c61a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
@@ -25,7 +25,6 @@
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.smartspace.filters.LockscreenAndDreamTargetFilter
@@ -52,7 +51,6 @@
 
 @SmallTest
 @TestableLooper.RunWithLooper
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class LockscreenAndDreamTargetFilterTest : SysuiTestCase() {
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
index a7c223d..0b5aea7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
@@ -19,7 +19,6 @@
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -36,7 +35,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class LockscreenPreconditionTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 14e58e5..e8923a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -5,41 +5,32 @@
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
 import com.android.systemui.ExpandHelper
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
 import com.android.systemui.media.controls.ui.MediaHierarchyManager
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.qs.QS
-import com.android.systemui.power.domain.interactor.PowerInteractorFactory
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeViewController
-import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
-import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
 import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
 import com.android.systemui.statusbar.policy.FakeConfigurationController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.user.domain.UserDomainLayerModule
+import dagger.BindsInstance
+import dagger.Component
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import org.junit.After
 import org.junit.Assert.assertFalse
@@ -60,9 +51,8 @@
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.junit.MockitoJUnit
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
 
 private fun <T> anyObject(): T {
     return Mockito.anyObject<T>()
@@ -73,68 +63,38 @@
 @RunWith(AndroidTestingRunner::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
-    private val utils = SceneTestUtils(this)
-    private val testScope = utils.testScope
 
-    lateinit var transitionController: LockscreenShadeTransitionController
+    private lateinit var testComponent: TestComponent
+
+    private val transitionController
+        get() = testComponent.transitionController
+    private val configurationController
+        get() = testComponent.configurationController
+    private val disableFlagsRepository
+        get() = testComponent.disableFlagsRepository
+    private val testScope
+        get() = testComponent.testScope
+
     lateinit var row: ExpandableNotificationRow
-    @Mock lateinit var statusbarStateController: SysuiStatusBarStateController
-    @Mock lateinit var logger: LSShadeTransitionLogger
-    @Mock lateinit var dumpManager: DumpManager
+
+    @Mock lateinit var centralSurfaces: CentralSurfaces
+    @Mock lateinit var depthController: NotificationShadeDepthController
+    @Mock lateinit var expandHelperCallback: ExpandHelper.Callback
     @Mock lateinit var keyguardBypassController: KeyguardBypassController
     @Mock lateinit var lockScreenUserManager: NotificationLockscreenUserManager
-    @Mock lateinit var falsingCollector: FalsingCollector
-    @Mock lateinit var ambientState: AmbientState
-    @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle
     @Mock lateinit var mediaHierarchyManager: MediaHierarchyManager
-    @Mock lateinit var scrimController: ScrimController
-    @Mock lateinit var falsingManager: FalsingManager
-    @Mock lateinit var shadeViewController: ShadeViewController
     @Mock lateinit var nsslController: NotificationStackScrollLayoutController
-    @Mock lateinit var depthController: NotificationShadeDepthController
-    @Mock lateinit var stackscroller: NotificationStackScrollLayout
-    @Mock lateinit var expandHelperCallback: ExpandHelper.Callback
-    @Mock lateinit var mCentralSurfaces: CentralSurfaces
     @Mock lateinit var qS: QS
-    @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
-    @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
-    @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
-    @Mock lateinit var activityStarter: ActivityStarter
+    @Mock lateinit var scrimController: ScrimController
+    @Mock lateinit var shadeViewController: ShadeViewController
+    @Mock lateinit var stackscroller: NotificationStackScrollLayout
+    @Mock lateinit var statusbarStateController: SysuiStatusBarStateController
     @Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
-    private val sceneContainerFlags = FakeSceneContainerFlags()
-    private val sceneInteractor = utils.sceneInteractor()
-    private val disableFlagsRepository = FakeDisableFlagsRepository()
-    private val keyguardRepository = FakeKeyguardRepository()
-    private val configurationRepository = FakeConfigurationRepository()
-    private val sharedNotificationContainerInteractor = SharedNotificationContainerInteractor(
-        configurationRepository,
-        mContext,
-            ResourcesSplitShadeStateController()
-    )
-    private val shadeInteractor =
-        ShadeInteractor(
-            testScope.backgroundScope,
-            disableFlagsRepository,
-            sceneContainerFlags,
-            { sceneInteractor },
-            keyguardRepository,
-            userSetupRepository = FakeUserSetupRepository(),
-            deviceProvisionedController = mock(),
-            userInteractor = mock(),
-            sharedNotificationContainerInteractor,
-            repository = FakeShadeRepository(),
-        )
-    private val powerInteractor = PowerInteractorFactory.create().powerInteractor
-    @JvmField @Rule val mockito = MockitoJUnit.rule()
 
-    private val configurationController = FakeConfigurationController()
+    @JvmField @Rule val mockito = MockitoJUnit.rule()
 
     @Before
     fun setup() {
-        // By default, have the shade enabled
-        disableFlagsRepository.disableFlags.value = DisableFlagsModel()
-        testScope.runCurrent()
-
         val helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
         row = helper.createRow()
         context
@@ -143,55 +103,9 @@
         context
             .getOrCreateTestableResources()
             .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
-        transitionController =
-            LockscreenShadeTransitionController(
-                statusBarStateController = statusbarStateController,
-                logger = logger,
-                keyguardBypassController = keyguardBypassController,
-                lockScreenUserManager = lockScreenUserManager,
-                falsingCollector = falsingCollector,
-                ambientState = ambientState,
-                mediaHierarchyManager = mediaHierarchyManager,
-                depthController = depthController,
-                wakefulnessLifecycle = wakefulnessLifecycle,
-                context = context,
-                configurationController = configurationController,
-                falsingManager = falsingManager,
-                dumpManager = dumpManager,
-                splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
-                singleShadeOverScrollerFactory = { singleShadeOverScroller },
-                scrimTransitionController =
-                    LockscreenShadeScrimTransitionController(
-                        scrimController,
-                        context,
-                        configurationController,
-                        dumpManager,
-                            ResourcesSplitShadeStateController()
-                    ),
-                keyguardTransitionControllerFactory = { notificationPanelController ->
-                    LockscreenShadeKeyguardTransitionController(
-                        mediaHierarchyManager,
-                        notificationPanelController,
-                        context,
-                        configurationController,
-                        dumpManager,
-                            ResourcesSplitShadeStateController()
-                    )
-                },
-                qsTransitionControllerFactory = { qsTransitionController },
-                activityStarter = activityStarter,
-                shadeRepository = FakeShadeRepository(),
-                shadeInteractor = shadeInteractor,
-                powerInteractor = powerInteractor,
-                splitShadeStateController = ResourcesSplitShadeStateController()
-            )
-        transitionController.addCallback(transitionControllerCallback)
+
         whenever(nsslController.view).thenReturn(stackscroller)
         whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
-        transitionController.shadeViewController = shadeViewController
-        transitionController.centralSurfaces = mCentralSurfaces
-        transitionController.qS = qS
-        transitionController.setStackScroller(nsslController)
         whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)
         whenever(nsslController.isInLockedDownShade).thenReturn(false)
         whenever(qS.isFullyCollapsed).thenReturn(true)
@@ -199,9 +113,36 @@
             .thenReturn(true)
         whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)
         whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true)
-        whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false)
         whenever(keyguardBypassController.bypassEnabled).thenReturn(false)
-        clearInvocations(mCentralSurfaces)
+
+        testComponent =
+            DaggerLockscreenShadeTransitionControllerTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, false)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            notificationShadeDepthController = depthController,
+                            keyguardBypassController = keyguardBypassController,
+                            mediaHierarchyManager = mediaHierarchyManager,
+                            notificationLockscreenUserManager = lockScreenUserManager,
+                            notificationStackScrollLayoutController = nsslController,
+                            scrimController = scrimController,
+                            statusBarStateController = statusbarStateController,
+                        )
+                )
+
+        transitionController.addCallback(transitionControllerCallback)
+        transitionController.shadeViewController = shadeViewController
+        transitionController.centralSurfaces = centralSurfaces
+        transitionController.qS = qS
+        transitionController.setStackScroller(nsslController)
+        clearInvocations(centralSurfaces)
+
+        testScope.runCurrent()
     }
 
     @After
@@ -282,7 +223,7 @@
         transitionController.goToLockedShade(null)
         verify(statusbarStateController, never()).setState(anyInt())
         verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)
-        verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
+        verify(centralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
     }
 
     @Test
@@ -318,7 +259,7 @@
         verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(transitionControllerCallback, never())
             .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
-        verify(qsTransitionController, never()).dragDownAmount = anyFloat()
+        verify(qS, never()).setTransitionToFullShadeProgress(anyBoolean(), anyFloat(), anyFloat())
     }
 
     @Test
@@ -329,7 +270,7 @@
         verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(transitionControllerCallback)
             .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
-        verify(qsTransitionController).dragDownAmount = 10f
+        verify(qS).setTransitionToFullShadeProgress(eq(true), anyFloat(), anyFloat())
         verify(depthController).transitionToFullShadeProgress = anyFloat()
     }
 
@@ -532,8 +473,8 @@
 
         transitionController.dragDownAmount = 10f
 
-        verify(singleShadeOverScroller).expansionDragDownAmount = 10f
-        verifyZeroInteractions(splitShadeOverScroller)
+        verify(nsslController).setOverScrollAmount(0)
+        verify(scrimController, never()).setNotificationsOverScrollAmount(anyInt())
     }
 
     @Test
@@ -542,8 +483,8 @@
 
         transitionController.dragDownAmount = 10f
 
-        verify(splitShadeOverScroller).expansionDragDownAmount = 10f
-        verifyZeroInteractions(singleShadeOverScroller)
+        verify(nsslController).setOverScrollAmount(0)
+        verify(scrimController).setNotificationsOverScrollAmount(0)
     }
 
     @Test
@@ -591,6 +532,32 @@
         progress: Float,
         lockScreenNotificationsProgress: Float
     ) {
-        scrimController.setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
+        setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
+    }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val transitionController: LockscreenShadeTransitionController
+
+        val configurationController: FakeConfigurationController
+        val disableFlagsRepository: FakeDisableFlagsRepository
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
index fbb8ebf..20e5c43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
@@ -29,9 +29,9 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.util.mockito.mock
 import org.junit.Before
 import org.junit.Test
@@ -52,7 +52,7 @@
     private val collapsedHeight = 300
     private val wakeUpCoordinator: NotificationWakeUpCoordinator = mock()
     private val bypassController: KeyguardBypassController = mock()
-    private val headsUpManager: HeadsUpManagerPhone = mock()
+    private val headsUpManager: HeadsUpManager = mock()
     private val roundnessManager: NotificationRoundnessManager = mock()
     private val configurationController: ConfigurationController = mock()
     private val statusBarStateController: StatusBarStateController = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
index 5b919d9..3fef1d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
@@ -72,7 +72,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        `when`(wifiPickerTrackerFactory.create(any(), any())).thenReturn(wifiPickerTracker)
+        `when`(wifiPickerTrackerFactory.create(any(), any(), any())).thenReturn(wifiPickerTracker)
 
         `when`(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntryConnected)
         `when`(wifiPickerTracker.wifiEntries).thenReturn(ArrayList<WifiEntry>().apply {
@@ -165,7 +165,7 @@
 
     @Test
     fun testReturnEmptyListWhenNoWifiPickerTracker() {
-        `when`(wifiPickerTrackerFactory.create(any(), any())).thenReturn(null)
+        `when`(wifiPickerTrackerFactory.create(any(), any(), any())).thenReturn(null)
         val otherController = AccessPointControllerImpl(
                 userManager,
                 userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt
new file mode 100644
index 0000000..f1e6a05
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 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.statusbar.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeKeyguardStatusBarRepository : KeyguardStatusBarRepository {
+    override val isKeyguardUserSwitcherEnabled = MutableStateFlow(false)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
new file mode 100644
index 0000000..b1c994c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2023 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.statusbar.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.user.data.repository.FakeUserSwitcherRepository
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.mockito.Mockito.verify
+
+@SmallTest
+class KeyguardStatusBarRepositoryImplTest : SysuiTestCase() {
+    private val testScope = TestScope()
+    private val configurationController = mock<ConfigurationController>()
+    private val userSwitcherRepository = FakeUserSwitcherRepository()
+
+    val underTest =
+        KeyguardStatusBarRepositoryImpl(
+            context,
+            configurationController,
+            userSwitcherRepository,
+        )
+
+    private val configurationListener: ConfigurationController.ConfigurationListener
+        get() {
+            val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
+            verify(configurationController).addCallback(capture(captor))
+            return captor.value
+        }
+
+    @Test
+    fun isKeyguardUserSwitcherEnabled_switcherNotEnabled_false() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isKeyguardUserSwitcherEnabled)
+
+            userSwitcherRepository.isEnabled.value = false
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isKeyguardUserSwitcherEnabled_keyguardConfigNotEnabled_false() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isKeyguardUserSwitcherEnabled)
+            userSwitcherRepository.isEnabled.value = true
+
+            context.orCreateTestableResources.addOverride(R.bool.config_keyguardUserSwitcher, false)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isKeyguardUserSwitcherEnabled_switchEnabledAndKeyguardConfigEnabled_true() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isKeyguardUserSwitcherEnabled)
+
+            userSwitcherRepository.isEnabled.value = true
+            context.orCreateTestableResources.addOverride(R.bool.config_keyguardUserSwitcher, true)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun isKeyguardUserSwitcherEnabled_refetchedOnSmallestWidthChanged() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isKeyguardUserSwitcherEnabled)
+            userSwitcherRepository.isEnabled.value = true
+            context.orCreateTestableResources.addOverride(R.bool.config_keyguardUserSwitcher, true)
+            assertThat(latest).isTrue()
+
+            context.orCreateTestableResources.addOverride(R.bool.config_keyguardUserSwitcher, false)
+            configurationListener.onSmallestScreenWidthChanged()
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isKeyguardUserSwitcherEnabled_refetchedOnDensityChanged() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isKeyguardUserSwitcherEnabled)
+            userSwitcherRepository.isEnabled.value = true
+            context.orCreateTestableResources.addOverride(R.bool.config_keyguardUserSwitcher, true)
+            assertThat(latest).isTrue()
+
+            context.orCreateTestableResources.addOverride(R.bool.config_keyguardUserSwitcher, false)
+            configurationListener.onDensityOrFontScaleChanged()
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isKeyguardUserSwitcherEnabled_refetchedOnEnabledChanged() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isKeyguardUserSwitcherEnabled)
+
+            userSwitcherRepository.isEnabled.value = false
+            context.orCreateTestableResources.addOverride(R.bool.config_keyguardUserSwitcher, true)
+            assertThat(latest).isFalse()
+
+            // WHEN the switcher becomes enabled but the keyguard switcher becomes disabled
+            context.orCreateTestableResources.addOverride(R.bool.config_keyguardUserSwitcher, false)
+            userSwitcherRepository.isEnabled.value = true
+
+            // THEN the value is still false because the keyguard config is refetched
+            assertThat(latest).isFalse()
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
index d86f8bb..235ac5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
@@ -8,15 +8,15 @@
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.HeadsUpUtil
-import com.android.systemui.res.R
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
 import kotlinx.coroutines.test.TestScope
@@ -37,7 +37,7 @@
 @RunWithLooper
 class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
     @Mock lateinit var notificationListContainer: NotificationListContainer
-    @Mock lateinit var headsUpManager: HeadsUpManagerPhone
+    @Mock lateinit var headsUpManager: HeadsUpManager
     @Mock lateinit var jankMonitor: InteractionJankMonitor
     @Mock lateinit var onFinishAnimationCallback: Runnable
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 257cc5b..4f1581c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -43,8 +43,8 @@
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
 import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
@@ -87,7 +87,7 @@
 
     private val notifPipeline: NotifPipeline = mock()
     private val logger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
-    private val headsUpManager: HeadsUpManager = mock()
+    private val headsUpManager: HeadsUpManagerPhone = mock()
     private val headsUpViewBinder: HeadsUpViewBinder = mock()
     private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock()
     private val remoteInputManager: NotificationRemoteInputManager = mock()
@@ -435,7 +435,7 @@
 
     private fun addHUN(entry: NotificationEntry) {
         huns.add(entry)
-        whenever(headsUpManager.topEntry).thenReturn(entry)
+        whenever(headsUpManager.getTopEntry()).thenReturn(entry)
         onHeadsUpChangedListener.onHeadsUpStateChanged(entry, true)
         notifLifetimeExtender.cancelLifetimeExtension(entry)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index fbd61f4..546abd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -23,7 +23,6 @@
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.advanceTimeBy
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.dump.logcatLogBuffer
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -40,10 +39,10 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.util.mockito.any
@@ -247,7 +246,7 @@
             unseenFilter.onCleanup()
 
             // THEN: The SeenNotificationProvider has been updated to reflect the suppression
-            assertThat(seenNotificationsProvider.hasFilteredOutSeenNotifications).isTrue()
+            assertThat(notificationListInteractor.hasFilteredOutSeenNotifications.value).isTrue()
         }
     }
 
@@ -598,7 +597,7 @@
             FakeSettings().apply {
                 putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)
             }
-        val seenNotificationsProvider = SeenNotificationsProviderImpl()
+        val notificationListInteractor = NotificationListInteractor(NotificationListRepository())
         val keyguardCoordinator =
             KeyguardCoordinator(
                 testDispatcher,
@@ -611,7 +610,7 @@
                 testScope.backgroundScope,
                 sectionHeaderVisibilityProvider,
                 fakeSettings,
-                seenNotificationsProvider,
+                notificationListInteractor,
                 statusBarStateController,
             )
         keyguardCoordinator.attach(notifPipeline)
@@ -619,7 +618,7 @@
             KeyguardCoordinatorTestScope(
                     keyguardCoordinator,
                     testScope,
-                    seenNotificationsProvider,
+                    notificationListInteractor,
                     fakeSettings,
                 )
                 .testBlock()
@@ -629,7 +628,7 @@
     private inner class KeyguardCoordinatorTestScope(
         private val keyguardCoordinator: KeyguardCoordinator,
         private val scope: TestScope,
-        val seenNotificationsProvider: SeenNotificationsProvider,
+        val notificationListInteractor: NotificationListInteractor,
         private val fakeSettings: FakeSettings,
     ) : CoroutineScope by scope {
         val testScheduler: TestCoroutineScheduler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt
new file mode 100644
index 0000000..2f8f3bb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.mockito.Mockito.verify
+
+@SmallTest
+class NotificationsKeyguardViewStateRepositoryTest : SysuiTestCase() {
+
+    private val testComponent: TestComponent =
+        DaggerNotificationsKeyguardViewStateRepositoryTest_TestComponent.factory()
+            .create(test = this)
+
+    @Test
+    fun areNotifsFullyHidden_reflectsWakeUpCoordinator() =
+        with(testComponent) {
+            testScope.runTest {
+                whenever(mockWakeUpCoordinator.notificationsFullyHidden).thenReturn(false)
+                val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
+                runCurrent()
+
+                assertThat(notifsFullyHidden).isFalse()
+
+                withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
+                    .onFullyHiddenChanged(true)
+                runCurrent()
+
+                assertThat(notifsFullyHidden).isTrue()
+            }
+        }
+
+    @Test
+    fun isPulseExpanding_reflectsWakeUpCoordinator() =
+        with(testComponent) {
+            testScope.runTest {
+                whenever(mockWakeUpCoordinator.isPulseExpanding()).thenReturn(false)
+                val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
+                runCurrent()
+
+                assertThat(isPulseExpanding).isFalse()
+
+                withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
+                    .onPulseExpansionChanged(true)
+                runCurrent()
+
+                assertThat(isPulseExpanding).isTrue()
+            }
+        }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: NotificationsKeyguardViewStateRepositoryImpl
+
+        val mockWakeUpCoordinator: NotificationWakeUpCoordinator
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+            ): TestComponent
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
new file mode 100644
index 0000000..705a5a3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@SmallTest
+class NotificationsKeyguardInteractorTest : SysuiTestCase() {
+
+    private val testComponent: TestComponent =
+        DaggerNotificationsKeyguardInteractorTest_TestComponent.factory().create(test = this)
+
+    @Test
+    fun areNotifsFullyHidden_reflectsRepository() =
+        with(testComponent) {
+            testScope.runTest {
+                repository.setNotificationsFullyHidden(false)
+                val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
+                runCurrent()
+
+                assertThat(notifsFullyHidden).isFalse()
+
+                repository.setNotificationsFullyHidden(true)
+                runCurrent()
+
+                assertThat(notifsFullyHidden).isTrue()
+            }
+        }
+
+    @Test
+    fun isPulseExpanding_reflectsRepository() =
+        with(testComponent) {
+            testScope.runTest {
+                repository.setPulseExpanding(false)
+                val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
+                runCurrent()
+
+                assertThat(isPulseExpanding).isFalse()
+
+                repository.setPulseExpanding(true)
+                runCurrent()
+
+                assertThat(isPulseExpanding).isTrue()
+            }
+        }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: NotificationsKeyguardInteractor
+
+        val repository: FakeNotificationsKeyguardViewStateRepository
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(@BindsInstance test: SysuiTestCase): TestComponent
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
index b120c47..f72142f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FooterViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
@@ -11,10 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.row;
+package com.android.systemui.statusbar.notification.footer.ui.view;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -31,8 +31,8 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
index 7caa5ccc..e57986d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
@@ -26,9 +26,7 @@
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
 import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.phone.NotificationIconContainer
 import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.whenever
 import dagger.BindsInstance
 import dagger.Component
 import org.junit.Assert.assertFalse
@@ -37,7 +35,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -46,7 +43,6 @@
 class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase() {
 
     @Mock private lateinit var dozeParams: DozeParameters
-    @Mock private lateinit var aodIcons: NotificationIconContainer
 
     private lateinit var testComponent: TestComponent
     private val underTest
@@ -85,15 +81,6 @@
         assertTrue(underTest.shouldShowLowPriorityIcons())
     }
 
-    @Test
-    fun testAppearResetsTranslation() {
-        underTest.setupAodIcons(aodIcons)
-        whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
-        underTest.appearAodIcons()
-        verify(aodIcons).translationY = 0f
-        verify(aodIcons).alpha = 1.0f
-    }
-
     @SysUISingleton
     @Component(
         modules =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
new file mode 100644
index 0000000..31efebb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.ui.AnimatedValue
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
+
+    @Mock private lateinit var dozeParams: DozeParameters
+    @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController
+
+    private lateinit var testComponent: TestComponent
+    private val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
+        get() = testComponent.underTest
+    private val deviceEntryRepository: FakeDeviceEntryRepository
+        get() = testComponent.deviceEntryRepository
+    private val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        get() = testComponent.deviceProvisioningRepository
+    private val keyguardRepository: FakeKeyguardRepository
+        get() = testComponent.keyguardRepository
+    private val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        get() = testComponent.keyguardTransitionRepository
+    private val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository
+        get() = testComponent.notifsKeyguardRepository
+    private val powerRepository: FakePowerRepository
+        get() = testComponent.powerRepository
+    private val scope: TestScope
+        get() = testComponent.scope
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        testComponent =
+            DaggerNotificationIconContainerAlwaysOnDisplayViewModelTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            setDefault(Flags.FACE_AUTH_REFACTOR)
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+                            setDefault(Flags.NEW_AOD_TRANSITION)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            dozeParameters = dozeParams,
+                            screenOffAnimationController = screenOffAnimController,
+                        ),
+                )
+
+        keyguardRepository.setKeyguardShowing(true)
+        keyguardRepository.setKeyguardOccluded(false)
+        deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+        powerRepository.updateWakefulness(
+            rawState = WakefulnessState.AWAKE,
+            lastWakeReason = WakeSleepReason.OTHER,
+            lastSleepReason = WakeSleepReason.OTHER,
+        )
+    }
+
+    @Test
+    fun animationsEnabled_isFalse_whenFrpIsActive() =
+        scope.runTest {
+            deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_AOD,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_PULSING,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenNotAsleep() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenKeyguardIsShowing() =
+        scope.runTest {
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            runCurrent()
+
+            assertThat(animationsEnabled).isTrue()
+
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+
+            assertThat(animationsEnabled).isFalse()
+
+            keyguardRepository.setKeyguardShowing(false)
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun isDozing_startAodTransition() =
+        scope.runTest {
+            val isDozing by collectLastValue(underTest.isDozing)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            runCurrent()
+            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = true))
+        }
+
+    @Test
+    fun isDozing_startDozeTransition() =
+        scope.runTest {
+            val isDozing by collectLastValue(underTest.isDozing)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.DOZING,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            runCurrent()
+            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = false))
+        }
+
+    @Test
+    fun isDozing_startDozeToAodTransition() =
+        scope.runTest {
+            val isDozing by collectLastValue(underTest.isDozing)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.DOZING,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            runCurrent()
+            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = true))
+        }
+
+    @Test
+    fun isNotDozing_startAodToGoneTransition() =
+        scope.runTest {
+            val isDozing by collectLastValue(underTest.isDozing)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.GONE,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            runCurrent()
+            assertThat(isDozing).isEqualTo(AnimatedValue(false, isAnimating = true))
+        }
+
+    @Test
+    fun isDozing_stopAnimation() =
+        scope.runTest {
+            val isDozing by collectLastValue(underTest.isDozing)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.GONE,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            runCurrent()
+
+            underTest.completeDozeAnimation()
+            runCurrent()
+
+            assertThat(isDozing?.isAnimating).isEqualTo(false)
+        }
+
+    @Test
+    fun isNotVisible_pulseExpanding() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            notifsKeyguardRepository.setPulseExpanding(true)
+            runCurrent()
+
+            assertThat(isVisible?.value).isFalse()
+        }
+
+    @Test
+    fun isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    to = KeyguardState.GONE,
+                    transitionState = TransitionState.FINISHED,
+                )
+            )
+            whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false)
+            runCurrent()
+
+            assertThat(isVisible).isEqualTo(AnimatedValue(false, isAnimating = false))
+        }
+
+    @Test
+    fun isVisible_bypassEnabled() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            deviceEntryRepository.setBypassEnabled(true)
+            runCurrent()
+
+            assertThat(isVisible?.value).isTrue()
+        }
+
+    @Test
+    fun isNotVisible_pulseExpanding_notBypassing() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            notifsKeyguardRepository.setPulseExpanding(true)
+            deviceEntryRepository.setBypassEnabled(false)
+            runCurrent()
+
+            assertThat(isVisible?.value).isEqualTo(false)
+        }
+
+    @Test
+    fun isVisible_notifsFullyHidden_bypassEnabled() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
+            notifsKeyguardRepository.setPulseExpanding(false)
+            deviceEntryRepository.setBypassEnabled(true)
+            notifsKeyguardRepository.setNotificationsFullyHidden(true)
+            runCurrent()
+
+            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = true))
+        }
+
+    @Test
+    fun isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            notifsKeyguardRepository.setPulseExpanding(false)
+            deviceEntryRepository.setBypassEnabled(false)
+            whenever(dozeParams.alwaysOn).thenReturn(false)
+            notifsKeyguardRepository.setNotificationsFullyHidden(true)
+            runCurrent()
+
+            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = false))
+        }
+
+    @Test
+    fun isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            notifsKeyguardRepository.setPulseExpanding(false)
+            deviceEntryRepository.setBypassEnabled(false)
+            whenever(dozeParams.alwaysOn).thenReturn(true)
+            whenever(dozeParams.displayNeedsBlanking).thenReturn(true)
+            notifsKeyguardRepository.setNotificationsFullyHidden(true)
+            runCurrent()
+
+            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = false))
+        }
+
+    @Test
+    fun isVisible_notifsFullyHidden_bypassDisabled() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
+            notifsKeyguardRepository.setPulseExpanding(false)
+            deviceEntryRepository.setBypassEnabled(false)
+            whenever(dozeParams.alwaysOn).thenReturn(true)
+            whenever(dozeParams.displayNeedsBlanking).thenReturn(false)
+            notifsKeyguardRepository.setNotificationsFullyHidden(true)
+            runCurrent()
+
+            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = true))
+        }
+
+    @Test
+    fun isVisible_stopAnimation() =
+        scope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            notifsKeyguardRepository.setPulseExpanding(false)
+            deviceEntryRepository.setBypassEnabled(false)
+            whenever(dozeParams.alwaysOn).thenReturn(true)
+            whenever(dozeParams.displayNeedsBlanking).thenReturn(false)
+            notifsKeyguardRepository.setNotificationsFullyHidden(true)
+            runCurrent()
+
+            underTest.completeVisibilityAnimation()
+            runCurrent()
+
+            assertThat(isVisible?.isAnimating).isEqualTo(false)
+        }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                BiometricsDomainLayerModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
+
+        val deviceEntryRepository: FakeDeviceEntryRepository
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository
+        val powerRepository: FakePowerRepository
+        val scope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                mocks: TestMocksModule,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
new file mode 100644
index 0000000..e1e7f92
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
+import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
+
+    @Mock lateinit var dozeParams: DozeParameters
+
+    private lateinit var testComponent: TestComponent
+    private val underTest: NotificationIconContainerStatusBarViewModel
+        get() = testComponent.underTest
+    private val deviceProvisioningRepository
+        get() = testComponent.deviceProvisioningRepository
+    private val keyguardTransitionRepository
+        get() = testComponent.keyguardTransitionRepository
+    private val keyguardRepository
+        get() = testComponent.keyguardRepository
+    private val powerRepository
+        get() = testComponent.powerRepository
+    private val scope
+        get() = testComponent.scope
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        testComponent =
+            DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    // Configurable bindings
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FACE_AUTH_REFACTOR, value = false)
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            dozeParameters = dozeParams,
+                        ),
+                )
+
+        keyguardRepository.setKeyguardShowing(false)
+        deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+        powerRepository.updateWakefulness(
+            rawState = WakefulnessState.AWAKE,
+            lastWakeReason = WakeSleepReason.OTHER,
+            lastSleepReason = WakeSleepReason.OTHER,
+        )
+    }
+
+    @Test
+    fun animationsEnabled_isFalse_whenFrpIsActive() =
+        scope.runTest {
+            deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_AOD,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_PULSING,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenNotAsleep() =
+        scope.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @Test
+    fun animationsEnabled_isTrue_whenKeyguardIsNotShowing() =
+        scope.runTest {
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            keyguardRepository.setKeyguardShowing(true)
+            runCurrent()
+
+            assertThat(animationsEnabled).isFalse()
+
+            keyguardRepository.setKeyguardShowing(false)
+            runCurrent()
+
+            assertThat(animationsEnabled).isTrue()
+        }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                // Real impls
+                BiometricsDomainLayerModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: NotificationIconContainerStatusBarViewModel
+
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val powerRepository: FakePowerRepository
+        val scope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                mocks: TestMocksModule,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
index 8f39ee6..83f2a5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -62,11 +62,15 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.FakeGlobalSettings;
 import com.android.systemui.util.settings.FakeSettings;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.utils.os.FakeHandler;
 
+import dagger.BindsInstance;
+import dagger.Component;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -77,9 +81,6 @@
 import java.util.Map;
 import java.util.function.Consumer;
 
-import dagger.BindsInstance;
-import dagger.Component;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -93,7 +94,8 @@
     @Mock private HighPriorityProvider mHighPriorityProvider;
     @Mock private SysuiStatusBarStateController mStatusBarStateController;
     @Mock private UserTracker mUserTracker;
-    private final FakeSettings mFakeSettings = new FakeSettings();
+    private final FakeSettings mSecureSettings = new FakeSettings();
+    private final FakeGlobalSettings mGlobalSettings = new FakeGlobalSettings();
 
     private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
     private NotificationEntry mEntry;
@@ -113,8 +115,8 @@
                                 mHighPriorityProvider,
                                 mStatusBarStateController,
                                 mUserTracker,
-                                mFakeSettings,
-                                mFakeSettings);
+                                mSecureSettings,
+                                mGlobalSettings);
         mKeyguardNotificationVisibilityProvider = component.getProvider();
         for (CoreStartable startable : component.getCoreStartables().values()) {
             startable.start();
@@ -223,7 +225,7 @@
         Consumer<String> listener = mock(Consumer.class);
         mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
 
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
 
         verify(listener).accept(anyString());
     }
@@ -234,7 +236,7 @@
         Consumer<String> listener = mock(Consumer.class);
         mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
 
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, true);
 
         verify(listener).accept(anyString());
     }
@@ -242,8 +244,8 @@
     @Test
     public void hideSilentNotificationsPerUserSettingWithHighPriorityParent() {
         when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
         GroupEntry parent = new GroupEntryBuilder()
                 .setKey("parent")
                 .addChild(mEntry)
@@ -264,8 +266,8 @@
     @Test
     public void keyguardShowing_hideSilentNotifications_perUserSetting() {
         when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
         mEntry = new NotificationEntryBuilder()
                 .setUser(new UserHandle(NOTIF_USER_ID))
                 .setImportance(IMPORTANCE_LOW)
@@ -277,8 +279,8 @@
     @Test
     public void keyguardShowing_hideSilentNotifications_perUserSetting_withHighPriorityParent() {
         when(mKeyguardStateController.isShowing()).thenReturn(true);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
         GroupEntry parent = new GroupEntryBuilder()
                 .setKey("parent")
                 .addChild(mEntry)
@@ -300,10 +302,10 @@
     public void hideSilentOnLockscreenSetting() {
         // GIVEN an 'unfiltered-keyguard-showing' state and notifications shown on lockscreen
         setupUnfilteredState(mEntry);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
 
         // WHEN the show silent notifs on lockscreen setting is false
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
 
         // WHEN the notification is not high priority and not ambient
         mEntry = new NotificationEntryBuilder()
@@ -319,10 +321,10 @@
     public void showSilentOnLockscreenSetting() {
         // GIVEN an 'unfiltered-keyguard-showing' state and notifications shown on lockscreen
         setupUnfilteredState(mEntry);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
 
         // WHEN the show silent notifs on lockscreen setting is true
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true);
 
         // WHEN the notification is not high priority and not ambient
         mEntry = new NotificationEntryBuilder()
@@ -338,7 +340,7 @@
     public void defaultSilentOnLockscreenSettingIsHide() {
         // GIVEN an 'unfiltered-keyguard-showing' state and notifications shown on lockscreen
         setupUnfilteredState(mEntry);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
 
         // WHEN the notification is not high priority and not ambient
         mEntry = new NotificationEntryBuilder()
@@ -348,7 +350,8 @@
         when(mHighPriorityProvider.isExplicitlyHighPriority(any())).thenReturn(false);
 
         // WhHEN the show silent notifs on lockscreen setting is unset
-        assertNull(mFakeSettings.getString(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS));
+        assertNull(
+                mSecureSettings.getString(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS));
 
         assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
     }
@@ -359,7 +362,7 @@
         Consumer<String> listener = mock(Consumer.class);
         mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
 
-        mFakeSettings.putBool(Settings.Global.ZEN_MODE, true);
+        mGlobalSettings.putBool(Settings.Global.ZEN_MODE, true);
 
         verify(listener).accept(anyString());
     }
@@ -370,7 +373,7 @@
         Consumer<String> listener = mock(Consumer.class);
         mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
 
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true);
 
         verify(listener).accept(anyString());
     }
@@ -470,8 +473,8 @@
     public void highPriorityCharacteristicsIgnored() {
         // GIVEN an 'unfiltered-keyguard-showing' state with silent notifications hidden
         setupUnfilteredState(mEntry);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
 
         // WHEN the notification doesn't exceed the threshold to show on the lockscreen, but does
         // have the "high priority characteristics" that would promote it to high priority
@@ -557,7 +560,7 @@
                 .build());
 
         // WHEN its parent does exceed threshold tot show on the lockscreen
-        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
+        mSecureSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
         when(mHighPriorityProvider.isExplicitlyHighPriority(parent)).thenReturn(true);
 
         // THEN filter out the entry regardless of parent
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
index c9b77c5..9c20e54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
@@ -54,9 +54,9 @@
 import android.widget.TextView;
 
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -132,7 +132,8 @@
     public void testBindNotification_SetsTextApplicationName() {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
-                mMockNotificationRow, mAssistantFeedbackController);
+                mMockNotificationRow, mAssistantFeedbackController, mStatusBarService,
+                mNotificationGutsManager);
         final TextView textView = mFeedbackInfo.findViewById(R.id.pkg_name);
         assertTrue(textView.getText().toString().contains("App Name"));
     }
@@ -143,7 +144,8 @@
         when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
                 .thenReturn(iconDrawable);
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
-                mMockNotificationRow, mAssistantFeedbackController);
+                mMockNotificationRow, mAssistantFeedbackController, mStatusBarService,
+                mNotificationGutsManager);
         final ImageView iconView = mFeedbackInfo.findViewById(R.id.pkg_icon);
         assertEquals(iconDrawable, iconView.getDrawable());
     }
@@ -153,7 +155,7 @@
         when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
                 .thenReturn(STATUS_SILENCED);
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
-                mAssistantFeedbackController);
+                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was automatically demoted to Silent by the system. "
                         + "Let the developer know your feedback. Was this correct?",
@@ -165,7 +167,7 @@
         when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
                 .thenReturn(STATUS_PROMOTED);
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
-                mAssistantFeedbackController);
+                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was automatically ranked higher in your shade. "
                         + "Let the developer know your feedback. Was this correct?",
@@ -177,7 +179,7 @@
         when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
                 .thenReturn(STATUS_ALERTED);
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
-                mAssistantFeedbackController);
+                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was automatically promoted to Default by the system. "
                         + "Let the developer know your feedback. Was this correct?",
@@ -189,7 +191,7 @@
         when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
                 .thenReturn(STATUS_DEMOTED);
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
-                mAssistantFeedbackController);
+                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was automatically ranked lower in your shade. "
                         + "Let the developer know your feedback. Was this correct?",
@@ -199,7 +201,7 @@
     @Test
     public void testPositiveFeedback() {
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
-                mAssistantFeedbackController);
+                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
 
         final View yes = mFeedbackInfo.findViewById(R.id.yes);
         yes.performClick();
@@ -216,7 +218,7 @@
                 .thenReturn(true);
 
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
-                mAssistantFeedbackController);
+                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
 
         final View no = mFeedbackInfo.findViewById(R.id.no);
         no.performClick();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 9f2afdf..8a730cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -33,7 +33,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anySet;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
@@ -89,8 +88,8 @@
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -152,7 +151,7 @@
     @Mock private AssistantFeedbackController mAssistantFeedbackController;
     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     @Mock private StatusBarStateController mStatusBarStateController;
-    @Mock private HeadsUpManagerPhone mHeadsUpManagerPhone;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private ActivityStarter mActivityStarter;
 
     @Mock private UserManager mUserManager;
@@ -171,7 +170,7 @@
                 mTestScope.getBackgroundScope(),
                 new WindowRootViewVisibilityRepository(mBarService, mExecutor),
                 new FakeKeyguardRepository(),
-                mHeadsUpManagerPhone,
+                mHeadsUpManager,
                 PowerInteractorFactory.create().getPowerInteractor());
 
         mGutsManager = new NotificationGutsManager(
@@ -196,9 +195,10 @@
                 mWindowRootViewVisibilityInteractor,
                 mNotificationLockscreenUserManager,
                 mStatusBarStateController,
+                mBarService,
                 mDeviceProvisionedController,
                 mMetricsLogger,
-                mHeadsUpManagerPhone,
+                mHeadsUpManager,
                 mActivityStarter);
         mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
                 mOnSettingsClickListener);
@@ -239,7 +239,7 @@
                 anyInt(),
                 anyBoolean(),
                 any(Runnable.class));
-        verify(mHeadsUpManagerPhone).setGutsShown(realRow.getEntry(), true);
+        verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), true);
 
         assertEquals(View.VISIBLE, guts.getVisibility());
         mGutsManager.closeAndSaveGuts(false, false, true, 0, 0, false);
@@ -247,7 +247,7 @@
         verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
         verify(row, times(1)).setGutsView(any());
         mTestableLooper.processAllMessages();
-        verify(mHeadsUpManagerPhone).setGutsShown(realRow.getEntry(), false);
+        verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), false);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index ac680e6..cb73108 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -61,6 +61,7 @@
 import com.android.systemui.media.controls.util.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -81,14 +82,13 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
 import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
-import com.android.systemui.res.R;
 import com.android.systemui.wmshell.BubblesManager;
 import com.android.systemui.wmshell.BubblesTestActivity;
 
@@ -123,7 +123,7 @@
     private final GroupMembershipManager mGroupMembershipManager;
     private final GroupExpansionManager mGroupExpansionManager;
     private ExpandableNotificationRow mRow;
-    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final HeadsUpManager mHeadsUpManager;
     private final NotifBindPipeline mBindPipeline;
     private final NotifCollectionListener mBindPipelineEntryListener;
     private final RowContentBindStage mBindStage;
@@ -161,7 +161,7 @@
         mKeyguardBypassController = mock(KeyguardBypassController.class);
         mGroupMembershipManager = mock(GroupMembershipManager.class);
         mGroupExpansionManager = mock(GroupExpansionManager.class);
-        mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+        mHeadsUpManager = mock(HeadsUpManager.class);
         mIconManager = new IconManager(
                 mock(CommonNotifCollection.class),
                 mock(LauncherApps.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index ffe312b..20197e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -77,7 +77,6 @@
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
-import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.NotifStats;
@@ -88,13 +87,15 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
 import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback;
+import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor;
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.tuner.TunerService;
@@ -124,7 +125,7 @@
     @Mock private NotificationGutsManager mNotificationGutsManager;
     @Mock private NotificationsController mNotificationsController;
     @Mock private NotificationVisibilityProvider mVisibilityProvider;
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
     @Mock private TunerService mTunerService;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -170,8 +171,8 @@
     @Captor
     private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
 
-    private final SeenNotificationsProviderImpl mSeenNotificationsProvider =
-            new SeenNotificationsProviderImpl();
+    private final NotificationListInteractor mNotificationListInteractor =
+            new NotificationListInteractor(new NotificationListRepository());
 
     private NotificationStackScrollLayoutController mController;
 
@@ -503,7 +504,7 @@
     @Test
     public void testSetNotifStats_updatesHasFilteredOutSeenNotifications() {
         initController(/* viewIsAttached= */ true);
-        mSeenNotificationsProvider.setHasFilteredOutSeenNotifications(true);
+        mNotificationListInteractor.setHasFilteredOutSeenNotifications(true);
         mController.getNotifStackController().setNotifStats(NotifStats.getEmpty());
         verify(mNotificationStackScrollLayout).setHasFilteredOutSeenNotifications(true);
         verify(mNotificationStackScrollLayout).updateFooter();
@@ -703,7 +704,7 @@
                 mUiEventLogger,
                 mRemoteInputManager,
                 mVisibilityLocationProviderDelegator,
-                mSeenNotificationsProvider,
+                mNotificationListInteractor,
                 mShadeController,
                 mJankMonitor,
                 mStackLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 3a820e8..a2be8b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -65,12 +65,12 @@
 
 import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.systemui.ExpandHelper;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.EmptyShadeView;
@@ -81,9 +81,9 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.FooterView;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -163,6 +163,7 @@
         mFeatureFlags.setDefault(Flags.SENSITIVE_REVEAL_ANIM);
         mFeatureFlags.setDefault(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS);
         mFeatureFlags.setDefault(Flags.NOTIFICATION_SHELF_REFACTOR);
+        mFeatureFlags.setDefault(Flags.NEW_AOD_TRANSITION);
 
         // Inject dependencies before initializing the layout
         mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags);
@@ -247,25 +248,7 @@
     }
 
     @Test
-    public void testUpdateStackHeight_withDozeAmount_whenDozeChanging() {
-        final float dozeAmount = 0.5f;
-        mAmbientState.setDozeAmount(dozeAmount);
-
-        final float endHeight = 8f;
-        final float expansionFraction = 1f;
-        float expected = MathUtils.lerp(
-                endHeight * StackScrollAlgorithm.START_FRACTION,
-                endHeight, dozeAmount);
-
-        mStackScroller.updateStackHeight(endHeight, expansionFraction);
-        assertThat(mAmbientState.getStackHeight()).isEqualTo(expected);
-    }
-
-    @Test
     public void testUpdateStackHeight_withExpansionAmount_whenDozeNotChanging() {
-        final float dozeAmount = 1f;
-        mAmbientState.setDozeAmount(dozeAmount);
-
         final float endHeight = 8f;
         final float expansionFraction = 0.5f;
         final float expected = MathUtils.lerp(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index a52466d..49906dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -5,18 +5,18 @@
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ShadeInterpolation.getContentAlpha
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.res.R
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
 import com.android.systemui.statusbar.EmptyShadeView
 import com.android.systemui.statusbar.NotificationShelf
 import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView.FooterViewState
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
-import com.android.systemui.statusbar.notification.row.FooterView
-import com.android.systemui.statusbar.notification.row.FooterView.FooterViewState
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Expect
@@ -241,6 +241,8 @@
     fun resetViewStates_isOnKeyguard_viewBecomesTransparent() {
         ambientState.setStatusBarState(StatusBarState.KEYGUARD)
         ambientState.hideAmount = 0.25f
+        whenever(notificationRow.isHeadsUpState).thenReturn(true)
+
         stackScrollAlgorithm.initView(context)
 
         stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
@@ -283,17 +285,20 @@
         val row2 = mockExpandableNotificationRow()
         hostView.addView(row2)
 
+        whenever(row1.isHeadsUpState).thenReturn(true)
+        whenever(row2.isHeadsUpState).thenReturn(false)
+
         ambientState.setStatusBarState(StatusBarState.KEYGUARD)
         ambientState.hideAmount = 0.25f
+        ambientState.dozeAmount = 0.33f
         notificationShelf.viewState.hidden = true
         ambientState.shelf = notificationShelf
         stackScrollAlgorithm.initView(context)
 
         stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
 
-        val expected = 1f - ambientState.hideAmount
-        assertThat(row1.viewState.alpha).isEqualTo(expected)
-        assertThat(row2.viewState.alpha).isEqualTo(expected)
+        assertThat(row1.viewState.alpha).isEqualTo(1f - ambientState.hideAmount)
+        assertThat(row2.viewState.alpha).isEqualTo(1f - ambientState.dozeAmount)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index e254dd0..ac11ff2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -19,36 +19,35 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
+import com.android.SysUITestModule
+import com.android.TestMocksModule
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.res.R
 import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.domain.UserDomainLayerModule
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -60,29 +59,27 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class SharedNotificationContainerViewModelTest : SysuiTestCase() {
-    private val utils = SceneTestUtils(this)
 
-    private val testScope = utils.testScope
+    private lateinit var testComponent: TestComponent
 
-    private val disableFlagsRepository = FakeDisableFlagsRepository()
-    private val userSetupRepository = FakeUserSetupRepository()
-    private val shadeRepository = FakeShadeRepository()
-    private val keyguardRepository = FakeKeyguardRepository()
-    private val sceneContainerFlags = FakeSceneContainerFlags()
-    private val sceneInteractor = utils.sceneInteractor()
-
-    private lateinit var configurationRepository: FakeConfigurationRepository
-    private lateinit var sharedNotificationContainerInteractor:
-        SharedNotificationContainerInteractor
-    private lateinit var underTest: SharedNotificationContainerViewModel
-    private lateinit var keyguardInteractor: KeyguardInteractor
-    private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
-    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
-    private lateinit var shadeInteractor: ShadeInteractor
+    private val shadeRepository
+        get() = testComponent.shadeRepository
+    private val keyguardRepository
+        get() = testComponent.keyguardRepository
+    private val configurationRepository
+        get() = testComponent.configurationRepository
+    private val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
+        get() = testComponent.sharedNotificationContainerInteractor
+    private val underTest: SharedNotificationContainerViewModel
+        get() = testComponent.underTest
+    private val keyguardInteractor: KeyguardInteractor
+        get() = testComponent.keyguardInteractor
+    private val keyguardTransitionRepository
+        get() = testComponent.keyguardTransitionRepository
+    private val testScope
+        get() = testComponent.testScope
 
     @Mock private lateinit var notificationStackSizeCalculator: NotificationStackSizeCalculator
-    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
-    @Mock private lateinit var userInteractor: UserInteractor
     @Mock
     private lateinit var notificationStackScrollLayoutController:
         NotificationStackScrollLayoutController
@@ -94,43 +91,21 @@
         whenever(notificationStackScrollLayoutController.getView()).thenReturn(mock())
         whenever(notificationStackScrollLayoutController.getShelfHeight()).thenReturn(0)
 
-        configurationRepository = FakeConfigurationRepository()
-        KeyguardTransitionInteractorFactory.create(
-                scope = testScope.backgroundScope,
-            )
-            .also {
-                keyguardInteractor = it.keyguardInteractor
-                keyguardTransitionInteractor = it.keyguardTransitionInteractor
-                keyguardTransitionRepository = it.repository
-            }
-        sharedNotificationContainerInteractor =
-            SharedNotificationContainerInteractor(
-                configurationRepository,
-                mContext,
-                ResourcesSplitShadeStateController()
-            )
-        shadeInteractor =
-            ShadeInteractor(
-                testScope.backgroundScope,
-                disableFlagsRepository,
-                sceneContainerFlags,
-                { sceneInteractor },
-                keyguardRepository,
-                userSetupRepository,
-                deviceProvisionedController,
-                userInteractor,
-                sharedNotificationContainerInteractor,
-                shadeRepository,
-            )
-        underTest =
-            SharedNotificationContainerViewModel(
-                sharedNotificationContainerInteractor,
-                keyguardInteractor,
-                keyguardTransitionInteractor,
-                notificationStackSizeCalculator,
-                notificationStackScrollLayoutController,
-                shadeInteractor
-            )
+        testComponent =
+            DaggerSharedNotificationContainerViewModelTest_TestComponent.factory()
+                .create(
+                    test = this,
+                    featureFlags =
+                        FakeFeatureFlagsClassicModule {
+                            set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+                        },
+                    mocks =
+                        TestMocksModule(
+                            notificationStackSizeCalculator = notificationStackSizeCalculator,
+                            notificationStackScrollLayoutController =
+                                notificationStackScrollLayoutController,
+                        )
+                )
     }
 
     @Test
@@ -404,4 +379,34 @@
             )
         )
     }
+
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent {
+
+        val underTest: SharedNotificationContainerViewModel
+
+        val configurationRepository: FakeConfigurationRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keyguardInteractor: KeyguardInteractor
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val shadeRepository: FakeShadeRepository
+        val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
+    }
 }
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 416694b..1d8a346 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
@@ -50,15 +50,15 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dagger.NightDisplayListenerModule;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.ReduceBrightColorsController;
-import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.DataSaverController;
@@ -288,7 +288,7 @@
         inOrderSafety.verify(mSafetyController).removeCallback(any());
         inOrderSafety.verify(mSafetyController).addCallback(any());
 
-        SettingObserver setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
+        UserSettingObserver setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
         assertEquals(USER + 1, setting.getCurrentUser());
         assertTrue(setting.isListening());
     }
@@ -342,7 +342,7 @@
         inOrderSafety.verify(mSafetyController).removeCallback(any());
         inOrderSafety.verify(mSafetyController).addCallback(any());
 
-        SettingObserver setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
+        UserSettingObserver setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
         assertEquals(USER + 1, setting.getCurrentUser());
         assertFalse(setting.isListening());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index a5d3484..e7dad6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -57,6 +57,7 @@
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 
@@ -85,7 +86,7 @@
     private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock private KeyguardStateController mKeyguardStateController;
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index e33fa22..f18af61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -85,7 +85,6 @@
 import com.android.keyguard.TestScopeProvider;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.InitController;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -117,6 +116,7 @@
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.settings.brightness.BrightnessSliderController;
@@ -219,7 +219,7 @@
     @Mock private KeyguardIndicationController mKeyguardIndicationController;
     @Mock private NotificationStackScrollLayout mStackScroller;
     @Mock private NotificationStackScrollLayoutController mStackScrollerController;
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private NotificationPanelViewController mNotificationPanelViewController;
     @Mock private ShadeLogger mShadeLogger;
     @Mock private NotificationPanelView mNotificationPanelView;
@@ -336,6 +336,7 @@
         mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);
         // Set default value to avoid IllegalStateException.
         mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
+        mFeatureFlags.setDefault(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR);
         // For the Shade to respond to Back gesture, we must enable the event routing
         mFeatureFlags.set(Flags.WM_SHADE_ALLOW_BACK_GESTURE, true);
         // For the Shade to animate during the Back gesture, we must enable the animation flag.
@@ -343,6 +344,7 @@
         mFeatureFlags.set(Flags.LIGHT_REVEAL_MIGRATION, true);
         // Turn AOD on and toggle feature flag for jank fixes
         mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true);
+        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false);
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
 
         IThermalService thermalService = mock(IThermalService.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index ff6f40d5..593c587 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -53,6 +53,7 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -72,7 +73,7 @@
 
     private DozeServiceHost mDozeServiceHost;
 
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private ScrimController mScrimController;
     @Mock private DozeScrimController mDozeScrimController;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index ec6286b..d84bb72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -47,6 +47,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Assert;
@@ -72,7 +73,7 @@
     private ExpandableNotificationRow mRow;
     private NotificationEntry mEntry;
     private HeadsUpStatusBarView mHeadsUpStatusBarView;
-    private HeadsUpManagerPhone mHeadsUpManager;
+    private HeadsUpManager mHeadsUpManager;
     private View mOperatorNameView;
     private StatusBarStateController mStatusbarStateController;
     private PhoneStatusBarTransitions mPhoneStatusBarTransitions;
@@ -93,7 +94,7 @@
         mEntry = mRow.getEntry();
         mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
                 mock(TextView.class));
-        mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+        mHeadsUpManager = mock(HeadsUpManager.class);
         mOperatorNameView = new View(mContext);
         mStatusbarStateController = mock(StatusBarStateController.class);
         mPhoneStatusBarTransitions = mock(PhoneStatusBarTransitions.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 1bc522d..cda2a74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -32,8 +32,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 
 import org.junit.After;
@@ -71,7 +72,6 @@
     @Mock private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
     @Mock private ShadeExpansionStateManager mShadeExpansionStateManager;
     @Mock private UiEventLogger mUiEventLogger;
-    private boolean mLivesPastNormalTime;
 
     private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
         TestableHeadsUpManagerPhone(
@@ -149,7 +149,7 @@
 
     @Test
     public void testSnooze() {
-        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
+        final HeadsUpManager hmp = createHeadsUpManagerPhone();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         hmp.showNotification(entry);
@@ -160,7 +160,7 @@
 
     @Test
     public void testSwipedOutNotification() {
-        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
+        final HeadsUpManager hmp = createHeadsUpManagerPhone();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         hmp.showNotification(entry);
@@ -176,7 +176,7 @@
 
     @Test
     public void testCanRemoveImmediately_swipedOut() {
-        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
+        final HeadsUpManager hmp = createHeadsUpManagerPhone();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         hmp.showNotification(entry);
@@ -189,7 +189,7 @@
     @Ignore("b/141538055")
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
-        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
+        final HeadsUpManager hmp = createHeadsUpManagerPhone();
         final NotificationEntry earlierEntry = createEntry(/* id = */ 0);
         final NotificationEntry laterEntry = createEntry(/* id = */ 1);
         laterEntry.setRow(mRow);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index c0d248e..6484389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -64,12 +64,13 @@
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.SceneTestUtils;
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
 import com.android.systemui.shade.ShadeViewStateProvider;
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.data.repository.FakeKeyguardStatusBarRepository;
+import com.android.systemui.statusbar.domain.interactor.KeyguardStatusBarInteractor;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -156,7 +157,6 @@
     public void setup() throws Exception {
         mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, false);
         mShadeViewStateProvider = new TestShadeViewStateProvider();
-        mShadeViewStateProvider = new TestShadeViewStateProvider();
 
         MockitoAnnotations.initMocks(this);
 
@@ -176,7 +176,9 @@
         mViewModel =
                 new KeyguardStatusBarViewModel(
                         mTestScope.getBackgroundScope(),
-                        mKeyguardInteractor);
+                        mKeyguardInteractor,
+                        new KeyguardStatusBarInteractor(new FakeKeyguardStatusBarRepository()),
+                        mBatteryController);
 
         allowTestableLooperAsMainThread();
         TestableLooper.get(this).runWithLooper(() -> {
@@ -320,6 +322,15 @@
     }
 
     @Test
+    public void setBatteryListening_true_flagOn_callbackNotAdded() {
+        mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true);
+
+        mController.setBatteryListening(true);
+
+        verify(mBatteryController, never()).addCallback(any());
+    }
+
+    @Test
     public void updateTopClipping_viewClippingUpdated() {
         int viewTop = 20;
         mKeyguardStatusBarView.setTop(viewTop);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index bac8579..45e9224 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -33,6 +34,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+
 import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
 
 import android.service.trust.TrustAgentService;
@@ -173,8 +175,8 @@
         mFeatureFlags = new FakeFeatureFlags();
         mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM, true);
         mFeatureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false);
-        mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, true);
         mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
+        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false);
 
         when(mNotificationShadeWindowController.getWindowRootView())
                 .thenReturn(mNotificationShadeWindowView);
@@ -761,6 +763,30 @@
     }
 
     @Test
+    public void handleDispatchTouchEvent_alternateBouncerViewFlagEnabled() {
+        mStatusBarKeyguardViewManager.addCallback(mCallback);
+
+        // GIVEN alternate bouncer view flag enabled & the alternate bouncer is visible
+        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, true);
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // THEN the touch is not acted upon
+        verify(mCallback, never()).onTouch(any());
+    }
+
+    @Test
+    public void onInterceptTouch_alternateBouncerViewFlagEnabled() {
+        // GIVEN alternate bouncer view flag enabled & the alternate bouncer is visible
+        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, true);
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // THEN the touch is not intercepted
+        assertFalse(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+        ));
+    }
+
+    @Test
     public void handleDispatchTouchEvent_alternateBouncerNotVisible() {
         mStatusBarKeyguardViewManager.addCallback(mCallback);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 8013e5e..beac995 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -92,6 +92,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -218,7 +219,7 @@
                 mScreenOffAnimationController,
                 mStatusBarStateController).getPowerInteractor();
 
-        HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class);
+        HeadsUpManager headsUpManager = mock(HeadsUpManager.class);
         NotificationLaunchAnimatorControllerProvider notificationAnimationProvider =
                 new NotificationLaunchAnimatorControllerProvider(
                         new NotificationExpansionRepository(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 233f407..ee4f208 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -15,6 +15,7 @@
 package com.android.systemui.statusbar.phone;
 
 import static android.view.Display.DEFAULT_DISPLAY;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -59,6 +60,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
@@ -106,7 +108,7 @@
                 mContext,
                 shadeViewController,
                 mock(QuickSettingsController.class),
-                mock(HeadsUpManagerPhone.class),
+                mock(HeadsUpManager.class),
                 notificationShadeWindowView,
                 mock(ActivityStarter.class),
                 stackScrollLayoutController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
index d35ce76..8ecf6f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
@@ -18,12 +18,11 @@
 
 import android.os.Handler
 import android.os.Looper
-import android.os.UserHandle
 import android.provider.Settings.Global
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.FakeGlobalSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -48,15 +47,14 @@
     @Mock private lateinit var logger: TableLogBuffer
     private lateinit var bgHandler: Handler
     private lateinit var scope: CoroutineScope
-    private lateinit var settings: FakeSettings
+    private lateinit var settings: FakeGlobalSettings
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         bgHandler = Handler(Looper.getMainLooper())
         scope = CoroutineScope(IMMEDIATE)
-        settings = FakeSettings()
-        settings.userId = UserHandle.USER_ALL
+        settings = FakeGlobalSettings()
 
         underTest =
             AirplaneModeRepositoryImpl(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
index dbaa29b..d06a6e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -20,7 +20,6 @@
 import android.net.wifi.WifiManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.demomode.DemoMode
 import com.android.systemui.demomode.DemoModeController
@@ -53,7 +52,6 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WifiRepositorySwitcherTest : SysuiTestCase() {
     private lateinit var underTest: WifiRepositorySwitcher
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt
index 206ac1d..ce00250 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
@@ -28,7 +27,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class DisabledWifiRepositoryTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index c2e75aa..cf20ba8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -35,7 +35,6 @@
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.log.table.TableLogBuffer
@@ -73,7 +72,6 @@
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WifiRepositoryImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
index afab623..c2f5665 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
@@ -105,7 +105,7 @@
     fun setUp() {
         featureFlags.set(Flags.INSTANT_TETHER, false)
         featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, false)
-        whenever(wifiPickerTrackerFactory.create(any(), capture(callbackCaptor)))
+        whenever(wifiPickerTrackerFactory.create(any(), capture(callbackCaptor), any()))
             .thenReturn(wifiPickerTracker)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
index 1db8065..7fbbfc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
@@ -19,7 +19,6 @@
 import android.net.wifi.WifiManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
@@ -43,7 +42,6 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WifiInteractorImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index 49a2648..2d1a27f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -19,7 +19,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.AccessibilityContentDescriptions.WIFI_OTHER_DEVICE_CONNECTION
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.coroutines.collectLastValue
@@ -53,7 +52,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class WifiViewModelTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
index 6094135..361fa5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.util.time.FakeSystemClock
 import com.android.systemui.util.wrapper.BuildInfo
@@ -67,19 +68,22 @@
 
     private lateinit var mainExecutor: FakeExecutor
     private lateinit var testableLooper: TestableLooper
-    private lateinit var settings: FakeSettings
+    private lateinit var secureSettings: FakeSettings
+    private lateinit var globalSettings: FakeGlobalSettings
+
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         testableLooper = TestableLooper.get(this)
         mainExecutor = FakeExecutor(FakeSystemClock())
-        settings = FakeSettings()
+        secureSettings = FakeSettings()
+        globalSettings = FakeGlobalSettings()
         `when`(userTracker.userId).thenReturn(START_USER)
         whenever(buildInfo.isDebuggable).thenReturn(false)
         controller = DeviceProvisionedControllerImpl(
-                settings,
-                settings,
+                secureSettings,
+                globalSettings,
                 userTracker,
                 dumpManager,
                 buildInfo,
@@ -108,7 +112,7 @@
 
     @Test
     fun testProvisionedWhenCreated() {
-        settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
+        globalSettings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
         init()
 
         assertThat(controller.isDeviceProvisioned).isTrue()
@@ -116,7 +120,7 @@
 
     @Test
     fun testFrpActiveWhenCreated() {
-        settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+        globalSettings.putInt(Settings.Global.SECURE_FRP_MODE, 1)
         init()
 
         assertThat(controller.isFrpActive).isTrue()
@@ -124,7 +128,7 @@
 
     @Test
     fun testUserSetupWhenCreated() {
-        settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
+        secureSettings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
         init()
 
         assertThat(controller.isUserSetup(START_USER))
@@ -134,7 +138,7 @@
     fun testDeviceProvisionedChange() {
         init()
 
-        settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
+        globalSettings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
         testableLooper.processAllMessages() // background observer
 
         assertThat(controller.isDeviceProvisioned).isTrue()
@@ -144,7 +148,7 @@
     fun testFrpActiveChange() {
         init()
 
-        settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+        globalSettings.putInt(Settings.Global.SECURE_FRP_MODE, 1)
         testableLooper.processAllMessages() // background observer
 
         assertThat(controller.isFrpActive).isTrue()
@@ -154,7 +158,7 @@
     fun testUserSetupChange() {
         init()
 
-        settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
+        secureSettings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
         testableLooper.processAllMessages() // background observer
 
         assertThat(controller.isUserSetup(START_USER)).isTrue()
@@ -165,7 +169,7 @@
         init()
         val otherUser = 10
 
-        settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, otherUser)
+        secureSettings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, otherUser)
         testableLooper.processAllMessages() // background observer
 
         assertThat(controller.isUserSetup(START_USER)).isFalse()
@@ -175,7 +179,7 @@
     @Test
     fun testCurrentUserSetup() {
         val otherUser = 10
-        settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, otherUser)
+        secureSettings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, otherUser)
         init()
 
         assertThat(controller.isCurrentUserSetup).isFalse()
@@ -219,7 +223,7 @@
         init()
         controller.addCallback(listener)
 
-        settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
+        secureSettings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
         testableLooper.processAllMessages()
         mainExecutor.runAllReady()
 
@@ -234,7 +238,7 @@
         init()
         controller.addCallback(listener)
 
-        settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
+        globalSettings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
         testableLooper.processAllMessages()
         mainExecutor.runAllReady()
 
@@ -249,7 +253,7 @@
         init()
         controller.addCallback(listener)
 
-        settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+        globalSettings.putInt(Settings.Global.SECURE_FRP_MODE, 1)
         testableLooper.processAllMessages()
         mainExecutor.runAllReady()
 
@@ -266,9 +270,9 @@
         controller.removeCallback(listener)
 
         switchUser(10)
-        settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
-        settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
-        settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+        secureSettings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
+        globalSettings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
+        globalSettings.putInt(Settings.Global.SECURE_FRP_MODE, 1)
 
         testableLooper.processAllMessages()
         mainExecutor.runAllReady()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 64ebcd9..4f3f564 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -41,10 +41,13 @@
 import android.app.Person;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Region;
 import android.os.Handler;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
@@ -73,7 +76,7 @@
     private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
     @Mock private AccessibilityManagerWrapper mAccessibilityMgr;
 
-    private final class TestableHeadsUpManager extends HeadsUpManager {
+    private final class TestableHeadsUpManager extends BaseHeadsUpManager {
         TestableHeadsUpManager(Context context,
                 HeadsUpManagerLogger logger,
                 Handler handler,
@@ -85,9 +88,78 @@
             mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
             mStickyDisplayTime = TEST_STICKY_AUTO_DISMISS_TIME;
         }
+
+        // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
+        @Override
+        public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void addSwipedOutNotification(@NonNull String key) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void extendHeadsUp() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Nullable
+        @Override
+        public Region getTouchableRegion() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean isHeadsUpGoingAway() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void onExpandingFinished() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
+                boolean animate) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setRemoteInputActive(@NonNull NotificationEntry entry,
+                boolean remoteInputActive) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setTrackingHeadsUp(boolean tracking) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean shouldSwallowClick(@NonNull String key) {
+            throw new UnsupportedOperationException();
+        }
     }
 
-    private HeadsUpManager createHeadsUpManager() {
+    private BaseHeadsUpManager createHeadsUpManager() {
         return new TestableHeadsUpManager(mContext, mLogger, mTestHandler, mAccessibilityMgr,
                 mUiEventLoggerFake);
     }
@@ -165,9 +237,10 @@
 
     @Test
     public void testHunRemovedLogging() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = mock(HeadsUpManager.HeadsUpEntry.class);
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock(
+                BaseHeadsUpManager.HeadsUpEntry.class);
         headsUpEntry.mEntry = notifEntry;
 
         hum.onAlertEntryRemoved(headsUpEntry);
@@ -177,35 +250,37 @@
 
     @Test
     public void testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);
 
         // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
-        headsUpEntry.wasUnpinned = false;
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
+        headsUpEntry.mWasUnpinned = false;
 
         assertTrue(hum.shouldHeadsUpBecomePinned(notifEntry));
     }
 
     @Test
     public void testShouldHeadsUpBecomePinned_wasUnpinned_false() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);
 
         // Add notifEntry to ANM mAlertEntries map and make it unpinned
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
-        headsUpEntry.wasUnpinned = true;
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
+        headsUpEntry.mWasUnpinned = true;
 
         assertFalse(hum.shouldHeadsUpBecomePinned(notifEntry));
     }
 
     @Test
     public void testShouldHeadsUpBecomePinned_noFSI_false() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         assertFalse(hum.shouldHeadsUpBecomePinned(entry));
@@ -214,7 +289,7 @@
 
     @Test
     public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -228,7 +303,7 @@
 
     @Test
     public void testShowNotification_autoDismissesWithDefaultTimeout() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -242,7 +317,7 @@
 
     @Test
     public void testShowNotification_stickyForSomeTime_autoDismissesWithStickyTimeout() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -256,7 +331,7 @@
 
     @Test
     public void testShowNotification_sticky_neverAutoDismisses() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -278,7 +353,7 @@
 
     @Test
     public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(true);
 
@@ -292,7 +367,7 @@
 
     @Test
     public void testShowNotification_stickyForSomeTime_autoDismissesWithAccessibilityTimeout() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
         useAccessibilityTimeout(true);
 
@@ -306,7 +381,7 @@
 
     @Test
     public void testRemoveNotification_beforeMinimumDisplayTime() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -329,7 +404,7 @@
 
     @Test
     public void testRemoveNotification_afterMinimumDisplayTime() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
         useAccessibilityTimeout(false);
 
@@ -366,7 +441,7 @@
 
     @Test
     public void testRemoveNotification_releaseImmediately() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createEntry(/* id = */ 0);
 
         hum.showNotification(entry);
@@ -382,14 +457,15 @@
 
     @Test
     public void testIsSticky_rowPinnedAndExpanded_true() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
         when(mRow.isPinned()).thenReturn(true);
         notifEntry.setRow(mRow);
 
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
         headsUpEntry.setExpanded(true);
 
         assertTrue(hum.isSticky(notifEntry.getKey()));
@@ -397,20 +473,21 @@
 
     @Test
     public void testIsSticky_remoteInputActive_true() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
 
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
-        headsUpEntry.remoteInputActive = true;
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
+        headsUpEntry.mRemoteInputActive = true;
 
         assertTrue(hum.isSticky(notifEntry.getKey()));
     }
 
     @Test
     public void testIsSticky_hasFullScreenIntent_true() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);
 
         hum.showNotification(notifEntry);
@@ -421,7 +498,7 @@
 
     @Test
     public void testIsSticky_stickyForSomeTime_false() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);
 
         hum.showNotification(entry);
@@ -432,21 +509,22 @@
 
     @Test
     public void testIsSticky_false() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
 
         hum.showNotification(notifEntry);
 
-        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey());
+        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
+                notifEntry.getKey());
         headsUpEntry.setExpanded(false);
-        headsUpEntry.remoteInputActive = false;
+        headsUpEntry.mRemoteInputActive = false;
 
         assertFalse(hum.isSticky(notifEntry.getKey()));
     }
 
     @Test
     public void testCompareTo_withNullEntries() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
 
         hum.showNotification(alertEntry);
@@ -458,7 +536,7 @@
 
     @Test
     public void testCompareTo_withNonAlertEntries() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
 
         final NotificationEntry nonAlertEntry1 = new NotificationEntryBuilder().setTag(
                 "nae1").build();
@@ -474,9 +552,9 @@
 
     @Test
     public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
 
-        final HeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
         ongoingCall.setEntry(new NotificationEntryBuilder()
                 .setSbn(createSbn(/* id = */ 0,
                         new Notification.Builder(mContext, "")
@@ -484,9 +562,9 @@
                                 .setOngoing(true)))
                 .build());
 
-        final HeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
         activeRemoteInput.setEntry(createEntry(/* id = */ 1));
-        activeRemoteInput.remoteInputActive = true;
+        activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
         assertThat(activeRemoteInput.compareTo(ongoingCall)).isGreaterThan(0);
@@ -494,9 +572,9 @@
 
     @Test
     public void testAlertEntryCompareTo_incomingCallLessThanActiveRemoteInput() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
 
-        final HeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry();
         final Person person = new Person.Builder().setName("person").build();
         final PendingIntent intent = mock(PendingIntent.class);
         incomingCall.setEntry(new NotificationEntryBuilder()
@@ -506,9 +584,9 @@
                                         .forIncomingCall(person, intent, intent))))
                 .build());
 
-        final HeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
         activeRemoteInput.setEntry(createEntry(/* id = */ 1));
-        activeRemoteInput.remoteInputActive = true;
+        activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);
         assertThat(activeRemoteInput.compareTo(incomingCall)).isGreaterThan(0);
@@ -516,10 +594,10 @@
 
     @Test
     public void testPinEntry_logsPeek() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
 
         // Needs full screen intent in order to be pinned
-        final HeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry();
+        final BaseHeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry();
         entryToPin.setEntry(createFullScreenIntentEntry(/* id = */ 0));
 
         // Note: the standard way to show a notification would be calling showNotification rather
@@ -530,13 +608,13 @@
         hum.onAlertEntryAdded(entryToPin);
 
         assertEquals(1, mUiEventLoggerFake.numLogs());
-        assertEquals(HeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
+        assertEquals(BaseHeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
                 mUiEventLoggerFake.eventId(0));
     }
 
     @Test
     public void testSetUserActionMayIndirectlyRemove() {
-        final HeadsUpManager hum = createHeadsUpManager();
+        final BaseHeadsUpManager hum = createHeadsUpManager();
         final NotificationEntry notifEntry = createEntry(/* id = */ 0);
 
         hum.showNotification(notifEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index 66c5aaa..6825f65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -38,7 +38,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.ZenModeController.Callback;
-import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.FakeGlobalSettings;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -67,7 +67,7 @@
     UserTracker mUserTracker;
     private ZenModeControllerImpl mController;
 
-    private final FakeSettings mGlobalSettings = new FakeSettings();
+    private final FakeGlobalSettings mGlobalSettings = new FakeGlobalSettings();
 
     @Before
     public void setUp() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
new file mode 100644
index 0000000..12694ae
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.policy.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProvisioningRepositoryImplTest : SysuiTestCase() {
+
+    @Mock lateinit var deviceProvisionedController: DeviceProvisionedController
+
+    lateinit var underTest: DeviceProvisioningRepositoryImpl
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            DeviceProvisioningRepositoryImpl(
+                deviceProvisionedController,
+            )
+    }
+
+    @Test
+    fun isDeviceProvisioned_reflectsCurrentControllerState() = runTest {
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned)
+        assertThat(deviceProvisioned).isTrue()
+    }
+
+    @Test
+    fun isDeviceProvisioned_updatesWhenControllerStateChanges_toTrue() = runTest {
+        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned)
+        runCurrent()
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) }
+            .onDeviceProvisionedChanged()
+        assertThat(deviceProvisioned).isTrue()
+    }
+
+    @Test
+    fun isDeviceProvisioned_updatesWhenControllerStateChanges_toFalse() = runTest {
+        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned)
+        runCurrent()
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
+        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) }
+            .onDeviceProvisionedChanged()
+        assertThat(deviceProvisioned).isFalse()
+    }
+
+    @Test
+    fun isFrpActive_reflectsCurrentControllerState() = runTest {
+        whenever(deviceProvisionedController.isFrpActive).thenReturn(true)
+        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive)
+        assertThat(frpActive).isTrue()
+    }
+
+    @Test
+    fun isFrpActive_updatesWhenControllerStateChanges_toTrue() = runTest {
+        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive)
+        runCurrent()
+        whenever(deviceProvisionedController.isFrpActive).thenReturn(true)
+        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) }
+            .onFrpActiveChanged()
+        assertThat(frpActive).isTrue()
+    }
+
+    @Test
+    fun isFrpActive_updatesWhenControllerStateChanges_toFalse() = runTest {
+        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive)
+        runCurrent()
+        whenever(deviceProvisionedController.isFrpActive).thenReturn(false)
+        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) }
+            .onFrpActiveChanged()
+        assertThat(frpActive).isFalse()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index f4078d5..1bc346d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -29,13 +29,23 @@
 import com.android.systemui.scene.SceneTestUtils
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.data.repository.FakeKeyguardStatusBarRepository
+import com.android.systemui.statusbar.domain.interactor.KeyguardStatusBarInteractor
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
+import org.mockito.Mockito.verify
 
 @SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
 class KeyguardStatusBarViewModelTest : SysuiTestCase() {
     private val testScope = TestScope()
     private val sceneTestUtils = SceneTestUtils(this)
@@ -54,11 +64,18 @@
         ) {
             sceneTestUtils.sceneInteractor()
         }
+    private val keyguardStatusBarInteractor =
+        KeyguardStatusBarInteractor(
+            FakeKeyguardStatusBarRepository(),
+        )
+    private val batteryController = mock<BatteryController>()
 
     private val underTest =
         KeyguardStatusBarViewModel(
             testScope.backgroundScope,
             keyguardInteractor,
+            keyguardStatusBarInteractor,
+            batteryController,
         )
 
     @Test
@@ -102,4 +119,46 @@
 
             assertThat(latest).isTrue()
         }
+
+    @Test
+    fun isBatteryCharging_matchesCallback() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isBatteryCharging)
+            runCurrent()
+
+            val captor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
+            verify(batteryController).addCallback(capture(captor))
+            val callback = captor.value
+
+            callback.onBatteryLevelChanged(
+                /* level= */ 2,
+                /* pluggedIn= */ false,
+                /* charging= */ true,
+            )
+
+            assertThat(latest).isTrue()
+
+            callback.onBatteryLevelChanged(
+                /* level= */ 2,
+                /* pluggedIn= */ true,
+                /* charging= */ false,
+            )
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isBatteryCharging_unregistersWhenNotListening() =
+        testScope.runTest {
+            val job = underTest.isBatteryCharging.launchIn(this)
+            runCurrent()
+
+            val captor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
+            verify(batteryController).addCallback(capture(captor))
+
+            job.cancel()
+            runCurrent()
+
+            verify(batteryController).removeCallback(captor.value)
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/FakeUserSwitcherRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/FakeUserSwitcherRepository.kt
new file mode 100644
index 0000000..758fe93a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/FakeUserSwitcherRepository.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.user.data.repository
+
+import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeUserSwitcherRepository : UserSwitcherRepository {
+    override val isEnabled = MutableStateFlow(false)
+    override val userSwitcherStatus =
+        MutableStateFlow<UserSwitcherStatusModel>(UserSwitcherStatusModel.Disabled)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
index e249cec..0d78ae9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
@@ -29,7 +29,7 @@
 import com.android.systemui.user.data.model.SelectedUserModel
 import com.android.systemui.user.data.model.SelectionStatus
 import com.android.systemui.user.data.model.UserSwitcherSettingsModel
-import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.FakeGlobalSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -56,14 +56,14 @@
 
     private lateinit var underTest: UserRepositoryImpl
 
-    private lateinit var globalSettings: FakeSettings
+    private lateinit var globalSettings: FakeGlobalSettings
     private lateinit var tracker: FakeUserTracker
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        globalSettings = FakeSettings()
+        globalSettings = FakeGlobalSettings()
         tracker = FakeUserTracker()
     }
 
@@ -282,20 +282,17 @@
             com.android.internal.R.bool.config_expandLockScreenUserSwitcher,
             true,
         )
-        globalSettings.putIntForUser(
+        globalSettings.putInt(
             UserRepositoryImpl.SETTING_SIMPLE_USER_SWITCHER,
             if (isSimpleUserSwitcher) 1 else 0,
-            UserHandle.USER_SYSTEM,
         )
-        globalSettings.putIntForUser(
+        globalSettings.putInt(
             Settings.Global.ADD_USERS_WHEN_LOCKED,
             if (isAddUsersFromLockscreen) 1 else 0,
-            UserHandle.USER_SYSTEM,
         )
-        globalSettings.putIntForUser(
+        globalSettings.putInt(
             Settings.Global.USER_SWITCHER_ENABLED,
             if (isUserSwitcherEnabled) 1 else 0,
-            UserHandle.USER_SYSTEM,
         )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index af941d0..c56266d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -155,6 +155,9 @@
 
     @Test
     fun createUserInteractor_nonProcessUser_startsSecondaryService() {
+        val userId = Process.myUserHandle().identifier + 1
+        whenever(manager.aliveUsers).thenReturn(listOf(createUserInfo(userId, "abc")))
+
         createUserInteractor(false /* startAsProcessUser */)
         verify(spyContext).startServiceAsUser(any(), any())
     }
@@ -655,9 +658,10 @@
 
     @Test
     fun userSwitchedBroadcast() {
-        createUserInteractor()
         testScope.runTest {
             val userInfos = createUserInfos(count = 2, includeGuest = false)
+            whenever(manager.aliveUsers).thenReturn(userInfos)
+            createUserInteractor()
             userRepository.setUserInfos(userInfos)
             userRepository.setSelectedUserInfo(userInfos[0])
             userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
@@ -728,6 +732,26 @@
     }
 
     @Test
+    fun localeChanged_refreshUsers() {
+        createUserInteractor()
+        testScope.runTest {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            runCurrent()
+            val refreshUsersCallCount = userRepository.refreshUsersCallCount
+
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                spyContext,
+                Intent(Intent.ACTION_LOCALE_CHANGED)
+            )
+            runCurrent()
+
+            assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
+        }
+    }
+
+    @Test
     fun nonSystemUserUnlockedBroadcast_doNotRefreshUsers() {
         createUserInteractor()
         testScope.runTest {
@@ -985,6 +1009,13 @@
         }
     }
 
+    @Test
+    fun initWithNoAliveUsers() {
+        whenever(manager.aliveUsers).thenReturn(listOf())
+        createUserInteractor()
+        verify(spyContext, never()).startServiceAsUser(any(), any())
+    }
+
     private fun assertUsers(
         models: List<UserModel>?,
         count: Int,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 6932f5e..c236b12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.GuestResumeSessionReceiver
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.Text
+import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -347,6 +348,24 @@
         }
 
     @Test
+    fun isFinishRequested_finishesWhenUserButtonIsClicked() =
+        testScope.runTest {
+            setUsers(count = 2)
+            val isFinishRequested = mutableListOf<Boolean>()
+            val job =
+                launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
+
+            val userViewModels = collectLastValue(underTest.users)
+            assertThat(isFinishRequested.last()).isFalse()
+
+            userViewModels.invoke()?.firstOrNull()?.onClicked?.invoke()
+
+            assertThat(isFinishRequested.last()).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
     fun guestSelected_nameIsExitGuest() =
         testScope.runTest {
             val userInfos =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
new file mode 100644
index 0000000..aaf8d07
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2023 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.util.ui
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class AnimatedValueTest : SysuiTestCase() {
+
+    @Test
+    fun animatableEvent_updatesValue() = runTest {
+        val events = MutableSharedFlow<AnimatableEvent<Int>>()
+        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow())
+        val value by collectLastValue(values)
+        runCurrent()
+
+        events.emit(AnimatableEvent(value = 1, startAnimating = false))
+
+        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = false))
+    }
+
+    @Test
+    fun animatableEvent_startAnimation() = runTest {
+        val events = MutableSharedFlow<AnimatableEvent<Int>>()
+        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow())
+        val value by collectLastValue(values)
+        runCurrent()
+
+        events.emit(AnimatableEvent(value = 1, startAnimating = true))
+
+        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = true))
+    }
+
+    @Test
+    fun animatableEvent_startAnimation_alreadyAnimating() = runTest {
+        val events = MutableSharedFlow<AnimatableEvent<Int>>()
+        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow())
+        val value by collectLastValue(values)
+        runCurrent()
+
+        events.emit(AnimatableEvent(value = 1, startAnimating = true))
+        events.emit(AnimatableEvent(value = 2, startAnimating = true))
+
+        assertThat(value).isEqualTo(AnimatedValue(value = 2, isAnimating = true))
+    }
+
+    @Test
+    fun animatedValue_stopAnimating() = runTest {
+        val events = MutableSharedFlow<AnimatableEvent<Int>>()
+        val stopEvent = MutableSharedFlow<Unit>()
+        val values = events.toAnimatedValueFlow(completionEvents = stopEvent)
+        val value by collectLastValue(values)
+        runCurrent()
+
+        events.emit(AnimatableEvent(value = 1, startAnimating = true))
+        stopEvent.emit(Unit)
+
+        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = false))
+    }
+
+    @Test
+    fun animatedValue_stopAnimating_notAnimating() = runTest {
+        val events = MutableSharedFlow<AnimatableEvent<Int>>()
+        val stopEvent = MutableSharedFlow<Unit>()
+        val values = events.toAnimatedValueFlow(completionEvents = stopEvent)
+        values.launchIn(backgroundScope)
+        runCurrent()
+
+        events.emit(AnimatableEvent(value = 1, startAnimating = false))
+
+        assertThat(stopEvent.subscriptionCount.value).isEqualTo(0)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 28fc5db..b8f747b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -42,6 +42,7 @@
 import android.content.res.Configuration;
 import android.media.AudioManager;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Log;
@@ -70,6 +71,10 @@
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.FakeConfigurationController;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
+
+import dagger.Lazy;
 
 import org.junit.After;
 import org.junit.Before;
@@ -122,6 +127,8 @@
     @Mock CsdWarningDialog mCsdWarningDialog;
     @Mock
     DevicePostureController mPostureController;
+    @Mock
+    private Lazy<SecureSettings> mLazySecureSettings;
 
     private final CsdWarningDialog.Factory mCsdWarningDialogFactory =
             new CsdWarningDialog.Factory() {
@@ -133,6 +140,7 @@
 
     private FakeFeatureFlags mFeatureFlags;
     private int mLongestHideShowAnimationDuration = 250;
+    private FakeSettings mSecureSettings;
 
     @Rule
     public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
@@ -162,6 +170,10 @@
 
         mFeatureFlags = new FakeFeatureFlags();
 
+        mSecureSettings = new FakeSettings();
+
+        when(mLazySecureSettings.get()).thenReturn(mSecureSettings);
+
         mDialog = new VolumeDialogImpl(
                 getContext(),
                 mVolumeDialogController,
@@ -177,7 +189,8 @@
                 mPostureController,
                 mTestableLooper.getLooper(),
                 mDumpManager,
-                mFeatureFlags);
+                mFeatureFlags,
+                mLazySecureSettings);
         mDialog.init(0, null);
         State state = createShellState();
         mDialog.onStateChangedH(state);
@@ -242,6 +255,17 @@
     }
 
     @Test
+    public void testSetTimeoutValue_ComputeTimeout() {
+        mSecureSettings.putInt(Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, 7000);
+        Mockito.reset(mAccessibilityMgr);
+        mDialog.init(0, null);
+        mDialog.rescheduleTimeoutH();
+        verify(mAccessibilityMgr).getRecommendedTimeoutMillis(
+                7000,
+                AccessibilityManager.FLAG_CONTENT_CONTROLS);
+    }
+
+    @Test
     public void testComputeTimeout_tooltip() {
         Mockito.reset(mAccessibilityMgr);
         mDialog.showCaptionsTooltip();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 409ba48..c832702 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -86,20 +86,36 @@
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.keyguard.KeyguardSecurityModel;
 import com.android.launcher3.icons.BubbleIconFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.data.repository.FakePowerRepository;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.scene.FakeWindowRootViewComponent;
 import com.android.systemui.scene.SceneTestUtils;
+import com.android.systemui.scene.data.repository.SceneContainerRepository;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
+import com.android.systemui.scene.shared.logger.SceneLogger;
 import com.android.systemui.settings.FakeDisplayTracker;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
@@ -139,6 +155,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
 import com.android.systemui.user.domain.interactor.UserInteractor;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.WindowManagerShellWrapper;
@@ -329,6 +346,8 @@
     private UserHandle mUser0;
 
     private FakeBubbleProperties mBubbleProperties;
+    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor;
+    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;
 
     @Before
     public void setUp() throws Exception {
@@ -350,21 +369,94 @@
         when(mNotificationShadeWindowView.getViewTreeObserver())
                 .thenReturn(mock(ViewTreeObserver.class));
 
-        mShadeInteractor = new ShadeInteractor(
+
+        FakeDeviceProvisioningRepository deviceProvisioningRepository =
+                new FakeDeviceProvisioningRepository();
+        deviceProvisioningRepository.setDeviceProvisioned(true);
+        FakeKeyguardRepository keyguardRepository = new FakeKeyguardRepository();
+        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic();
+        FakeShadeRepository shadeRepository = new FakeShadeRepository();
+        FakePowerRepository powerRepository = new FakePowerRepository();
+        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository();
+
+        PowerInteractor powerInteractor = new PowerInteractor(
+                powerRepository,
+                new FalsingCollectorFake(),
+                mock(ScreenOffAnimationController.class),
+                mStatusBarStateController);
+
+        SceneInteractor sceneInteractor = new SceneInteractor(
                 mTestScope.getBackgroundScope(),
-                new FakeDisableFlagsRepository(),
-                new FakeSceneContainerFlags(),
-                mUtils::sceneInteractor,
-                new FakeKeyguardRepository(),
-                new FakeUserSetupRepository(),
-                mock(DeviceProvisionedController.class),
-                mock(UserInteractor.class),
-                new SharedNotificationContainerInteractor(
-                        new FakeConfigurationRepository(),
-                        mContext,
-                        new ResourcesSplitShadeStateController()),
-                new FakeShadeRepository()
-        );
+                new SceneContainerRepository(
+                        mTestScope.getBackgroundScope(),
+                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+                powerRepository,
+                mock(SceneLogger.class));
+
+        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
+                keyguardRepository,
+                new FakeCommandQueue(),
+                powerInteractor,
+                featureFlags,
+                sceneContainerFlags,
+                new FakeDeviceEntryRepository(),
+                new FakeKeyguardBouncerRepository(),
+                configurationRepository,
+                shadeRepository,
+                () -> sceneInteractor);
+
+        FakeKeyguardTransitionRepository keyguardTransitionRepository =
+                new FakeKeyguardTransitionRepository();
+
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                new KeyguardTransitionInteractor(
+                        mTestScope.getBackgroundScope(),
+                        keyguardTransitionRepository,
+                        () -> keyguardInteractor,
+                        () -> mFromLockscreenTransitionInteractor,
+                        () -> mFromPrimaryBouncerTransitionInteractor);
+
+        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                shadeRepository,
+                powerInteractor);
+
+        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
+                keyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                mTestScope.getBackgroundScope(),
+                keyguardInteractor,
+                featureFlags,
+                mock(KeyguardSecurityModel.class),
+                powerInteractor);
+
+        ResourcesSplitShadeStateController splitShadeStateController =
+                new ResourcesSplitShadeStateController();
+
+        mShadeInteractor =
+                new ShadeInteractor(
+                        mTestScope.getBackgroundScope(),
+                        deviceProvisioningRepository,
+                        new FakeDisableFlagsRepository(),
+                        mDozeParameters,
+                        sceneContainerFlags,
+                        () -> sceneInteractor,
+                        keyguardRepository,
+                        keyguardTransitionInteractor,
+                        powerInteractor,
+                        new FakeUserSetupRepository(),
+                        mock(UserInteractor.class),
+                        new SharedNotificationContainerInteractor(
+                                configurationRepository,
+                                mContext,
+                                splitShadeStateController),
+                        new FakeShadeRepository()
+                );
 
         mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(
                 mContext,
diff --git a/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java b/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
index 41dbc14..b820ca6 100644
--- a/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
+++ b/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
@@ -68,13 +68,26 @@
 
     private final Object mLock = new Object();
     private final TestHandler mTestHandler = new TestHandler();
+    private final long mStartTime;
+    private long mTotalTimeDelta = 0;
+
     /**
-     * initializing the start time with {@link SystemClock#uptimeMillis()} reduces the discrepancies
-     * with various internals of classes like ValueAnimator which can sometimes read that clock via
+     * Construct an AnimatorTestRule with a custom start time.
+     * @see #AnimatorTestRule()
+     */
+    public AnimatorTestRule(long startTime) {
+        mStartTime = startTime;
+    }
+
+    /**
+     * Construct an AnimatorTestRule with a start time of {@link SystemClock#uptimeMillis()}.
+     * Initializing the start time with this clock reduces the discrepancies with various internals
+     * of classes like ValueAnimator which can sometimes read that clock via
      * {@link android.view.animation.AnimationUtils#currentAnimationTimeMillis()}.
      */
-    private final long mStartTime = SystemClock.uptimeMillis();
-    private long mTotalTimeDelta = 0;
+    public AnimatorTestRule() {
+        this(SystemClock.uptimeMillis());
+    }
 
     @NonNull
     @Override
diff --git a/packages/SystemUI/tests/utils/src/android/animation/PlatformAnimatorIsolationRule.kt b/packages/SystemUI/tests/utils/src/android/animation/PlatformAnimatorIsolationRule.kt
index 43a26f3..ca5e1d0 100644
--- a/packages/SystemUI/tests/utils/src/android/animation/PlatformAnimatorIsolationRule.kt
+++ b/packages/SystemUI/tests/utils/src/android/animation/PlatformAnimatorIsolationRule.kt
@@ -41,7 +41,7 @@
         private fun onError() =
             exceptionDeferrer.fail(
                 "Test's animations are not isolated! " +
-                    "Did you forget to add an AnimatorTestRule to your test class?"
+                    "Did you forget to add an AnimatorTestRule as a @Rule?"
             )
 
         fun throwDeferred() = exceptionDeferrer.throwDeferred()
diff --git a/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt b/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt
index 7a97029..95335a6 100644
--- a/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt
+++ b/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt
@@ -37,7 +37,7 @@
         private fun onError() =
             exceptionDeferrer.fail(
                 "Test's animations are not isolated! " +
-                    "Did you forget to add an AnimatorTestRule to your test class?"
+                    "Did you forget to add an AnimatorTestRule as a @Rule?"
             )
 
         fun throwDeferred() = exceptionDeferrer.throwDeferred()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
index 0e59496..dc5fd95 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
@@ -15,21 +15,29 @@
  */
 package com.android.systemui
 
+import com.android.systemui.classifier.FakeClassifierModule
 import com.android.systemui.data.FakeSystemUiDataLayerModule
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.log.FakeUiEventLoggerModule
 import com.android.systemui.scene.FakeSceneModule
 import com.android.systemui.settings.FakeSettingsModule
+import com.android.systemui.statusbar.policy.FakeConfigurationControllerModule
+import com.android.systemui.statusbar.policy.FakeSplitShadeStateControllerModule
 import com.android.systemui.util.concurrency.FakeExecutorModule
+import com.android.systemui.util.time.FakeSystemClockModule
 import dagger.Module
 
 @Module(
     includes =
         [
+            FakeClassifierModule::class,
+            FakeConfigurationControllerModule::class,
             FakeExecutorModule::class,
             FakeFeatureFlagsClassicModule::class,
-            FakeSettingsModule::class,
             FakeSceneModule::class,
+            FakeSettingsModule::class,
+            FakeSplitShadeStateControllerModule::class,
+            FakeSystemClockModule::class,
             FakeSystemUiDataLayerModule::class,
             FakeUiEventLoggerModule::class,
         ]
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index cd009df..f7e0120 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -15,8 +15,6 @@
  */
 package com.android.systemui;
 
-import static com.android.systemui.animation.FakeDialogLaunchAnimatorKt.fakeDialogLaunchAnimator;
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
@@ -37,23 +35,15 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.uiautomator.UiDevice;
 
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.broadcast.FakeBroadcastDispatcher;
 import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger;
-import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
 
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
-import org.junit.ClassRule;
 import org.junit.Rule;
 import org.mockito.Mockito;
 
@@ -73,8 +63,8 @@
     private Handler mHandler;
 
     // set the lowest order so it's the outermost rule
-    @ClassRule(order = Integer.MIN_VALUE)
-    public static AndroidXAnimatorIsolationRule mAndroidXAnimatorIsolationRule =
+    @Rule(order = Integer.MIN_VALUE)
+    public AndroidXAnimatorIsolationRule mAndroidXAnimatorIsolationRule =
             new AndroidXAnimatorIsolationRule();
 
     @Rule
@@ -98,10 +88,7 @@
         if (isRobolectricTest()) {
             mContext = mContext.createDefaultDisplayContext();
         }
-        SystemUIInitializer initializer = new SystemUIInitializerImpl(mContext);
-        initializer.init(true);
-        mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency());
-        Dependency.setInstance(mDependency);
+        mDependency = SysuiTestDependencyKt.installSysuiTestDependency(mContext);
         mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(
                 mContext,
                 mContext.getMainExecutor(),
@@ -128,25 +115,6 @@
         // reference and are never sent to the Context. This will also prevent a real
         // BroadcastDispatcher from actually registering receivers.
         mDependency.injectTestDependency(BroadcastDispatcher.class, mFakeBroadcastDispatcher);
-        // A lot of tests get the FalsingManager, often via several layers of indirection.
-        // None of them actually need it.
-        mDependency.injectTestDependency(FalsingManager.class, new FalsingManagerFake());
-        mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
-
-        // A lot of tests get the LocalBluetoothManager, often via several layers of indirection.
-        // None of them actually need it.
-        mDependency.injectMockDependency(LocalBluetoothManager.class);
-
-        // Notifications tests are injecting one of these, causing many classes (including
-        // KeyguardUpdateMonitor to be created (injected).
-        // TODO(b/1531701009) Clean up NotificationContentView creation to prevent this
-        mDependency.injectMockDependency(SmartReplyController.class);
-
-        // Make sure that all tests on any SystemUIDialog does not crash because this dependency
-        // is missing (constructing the actual one would throw).
-        // TODO(b/219008720): Remove this.
-        mDependency.injectMockDependency(SystemUIDialogManager.class);
-        mDependency.injectTestDependency(DialogLaunchAnimator.class, fakeDialogLaunchAnimator());
     }
 
     protected boolean shouldFailOnLeakedReceiver() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt
new file mode 100644
index 0000000..c791f4f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt
@@ -0,0 +1,26 @@
+package com.android.systemui
+
+import android.annotation.SuppressLint
+import android.content.Context
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.animation.fakeDialogLaunchAnimator
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+
+@SuppressLint("VisibleForTests")
+fun installSysuiTestDependency(context: Context): TestableDependency {
+    val initializer: SystemUIInitializer = SystemUIInitializerImpl(context)
+    initializer.init(true)
+
+    val dependency = TestableDependency(initializer.sysUIComponent.createDependency())
+    Dependency.setInstance(dependency)
+
+    dependency.injectMockDependency(KeyguardUpdateMonitor::class.java)
+
+    // Make sure that all tests on any SystemUIDialog does not crash because this dependency
+    // is missing (constructing the actual one would throw).
+    // TODO(b/219008720): Remove this.
+    dependency.injectMockDependency(SystemUIDialogManager::class.java)
+    dependency.injectTestDependency(DialogLaunchAnimator::class.java, fakeDialogLaunchAnimator())
+    return dependency
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt
index 0ced19e..ba9c5ed 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt
@@ -28,11 +28,21 @@
  * advanced together.
  */
 class AnimatorTestRule : TestRule {
+    // Create the androidx rule, which initializes start time to SystemClock.uptimeMillis(),
+    // then copy that time to the platform rule so that the two clocks are in sync.
     private val androidxRule = androidx.core.animation.AnimatorTestRule()
-    private val platformRule = android.animation.AnimatorTestRule()
+    private val platformRule = android.animation.AnimatorTestRule(androidxRule.startTime)
     private val advanceAndroidXTimeBy =
         Consumer<Long> { timeDelta -> androidxRule.advanceTimeBy(timeDelta) }
 
+    /** Access the mStartTime field; bypassing the restriction of being on a looper thread. */
+    private val androidx.core.animation.AnimatorTestRule.startTime: Long
+        get() =
+            javaClass.getDeclaredField("mStartTime").let { field ->
+                field.isAccessible = true
+                field.getLong(this)
+            }
+
     /**
      * Chain is for simplicity not to force a particular order; order should not matter, because
      * each rule affects a different AnimationHandler classes, and no callbacks to code under test
@@ -55,4 +65,11 @@
         //  animation from one to start later than the other.
         platformRule.advanceTimeBy(timeDelta, advanceAndroidXTimeBy)
     }
+
+    /**
+     * Returns the current time in milliseconds tracked by the AnimationHandlers. Note that this is
+     * a different time than the time tracked by {@link SystemClock}.
+     */
+    val currentTime: Long
+        get() = androidxRule.currentTime
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt
new file mode 100644
index 0000000..8fa6695
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 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.authentication.data
+
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeAuthenticationRepositoryModule::class])
+object FakeAuthenticationDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
index 4fc3e3f..ddfe79a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -24,10 +24,17 @@
 import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
 import com.android.systemui.authentication.shared.model.AuthenticationResultModel
 import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.currentTime
 
 class FakeAuthenticationRepository(
     private val deviceEntryRepository: FakeDeviceEntryRepository,
@@ -201,3 +208,19 @@
         }
     }
 }
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@Module(includes = [FakeAuthenticationRepositoryModule.Bindings::class])
+object FakeAuthenticationRepositoryModule {
+    @Provides
+    @SysUISingleton
+    fun provideFake(
+        deviceEntryRepository: FakeDeviceEntryRepository,
+        scope: TestScope,
+    ) = FakeAuthenticationRepository(deviceEntryRepository, currentTime = { scope.currentTime })
+
+    @Module
+    interface Bindings {
+        @Binds fun bindFake(fake: FakeAuthenticationRepository): AuthenticationRepository
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt
new file mode 100644
index 0000000..23bad39
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 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.classifier
+
+import dagger.Module
+
+@Module(includes = [FakeFalsingCollectorModule::class, FakeFalsingManagerModule::class])
+object FakeClassifierModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt
new file mode 100644
index 0000000..92acc94
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 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.classifier
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface FakeFalsingCollectorModule {
+    @Binds @FalsingCollectorActual fun bindFake(fake: FalsingCollectorFake): FalsingCollector
+    @Binds fun bindFakeLegacy(fake: FalsingCollectorFake): FalsingCollector
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt
new file mode 100644
index 0000000..554fc75
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 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.classifier
+
+import com.android.systemui.plugins.FalsingManager
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface FakeFalsingManagerModule {
+    @Binds fun bindFake(fake: FalsingManagerFake): FalsingManager
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
index d47e88f..5038285 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -21,15 +21,19 @@
 import android.net.Uri;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.plugins.FalsingManager;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.inject.Inject;
+
 /**
  * Simple Fake for testing where {@link FalsingManager} is required.
  */
+@SysUISingleton
 public class FalsingManagerFake implements FalsingManager {
     private boolean mIsFalseTouch;
     private boolean mIsSimpleTap;
@@ -46,6 +50,10 @@
     private final List<FalsingBeliefListener> mFalsingBeliefListeners = new ArrayList<>();
     private final List<FalsingTapListener> mTapListeners = new ArrayList<>();
 
+    @Inject
+    public FalsingManagerFake() {
+    }
+
     @Override
     public void onSuccessfulUnlock() {
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalTutorialRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalTutorialRepository.kt
new file mode 100644
index 0000000..902e852
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalTutorialRepository.kt
@@ -0,0 +1,19 @@
+package com.android.systemui.communal.data.repository
+
+import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED
+import android.provider.Settings.Secure.HubModeTutorialState
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Fake implementation of [CommunalTutorialRepository] */
+class FakeCommunalTutorialRepository() : CommunalTutorialRepository {
+    private val _tutorialSettingState = MutableStateFlow(HUB_MODE_TUTORIAL_NOT_STARTED)
+    override val tutorialSettingState: StateFlow<Int> = _tutorialSettingState
+    override suspend fun setTutorialState(@HubModeTutorialState state: Int) {
+        setTutorialSettingState(state)
+    }
+
+    fun setTutorialSettingState(@HubModeTutorialState state: Int) {
+        _tutorialSettingState.value = state
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt
index f866932..cffbf02 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt
@@ -15,8 +15,10 @@
  */
 package com.android.systemui.data
 
+import com.android.systemui.authentication.data.FakeAuthenticationDataLayerModule
 import com.android.systemui.bouncer.data.repository.FakeBouncerDataLayerModule
 import com.android.systemui.common.ui.data.FakeCommonDataLayerModule
+import com.android.systemui.deviceentry.data.FakeDeviceEntryDataLayerModule
 import com.android.systemui.keyguard.data.FakeKeyguardDataLayerModule
 import com.android.systemui.power.data.FakePowerDataLayerModule
 import com.android.systemui.shade.data.repository.FakeShadeDataLayerModule
@@ -28,8 +30,10 @@
 @Module(
     includes =
         [
-            FakeCommonDataLayerModule::class,
+            FakeAuthenticationDataLayerModule::class,
             FakeBouncerDataLayerModule::class,
+            FakeCommonDataLayerModule::class,
+            FakeDeviceEntryDataLayerModule::class,
             FakeKeyguardDataLayerModule::class,
             FakePowerDataLayerModule::class,
             FakeShadeDataLayerModule::class,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
new file mode 100644
index 0000000..ef02bdd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 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.deviceentry.data
+
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeDeviceEntryRepositoryModule::class]) object FakeDeviceEntryDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt
new file mode 100644
index 0000000..f4feee1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 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.deviceentry.data.repository
+
+import dagger.Module
+
+@Module(includes = [FakeDeviceEntryRepositoryModule::class]) object FakeDeviceEntryDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
index 5e60a09..f029348 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
@@ -1,22 +1,40 @@
+/*
+ * Copyright (C) 2023 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.deviceentry.data.repository
 
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 
 /** Fake implementation of [DeviceEntryRepository] */
-class FakeDeviceEntryRepository : DeviceEntryRepository {
+@SysUISingleton
+class FakeDeviceEntryRepository @Inject constructor() : DeviceEntryRepository {
 
     private var isInsecureLockscreenEnabled = true
-    private var isBypassEnabled = false
+
+    private val _isBypassEnabled = MutableStateFlow(false)
+    override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled
 
     private val _isUnlocked = MutableStateFlow(false)
     override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
 
-    override fun isBypassEnabled(): Boolean {
-        return isBypassEnabled
-    }
-
     override suspend fun isInsecureLockscreenEnabled(): Boolean {
         return isInsecureLockscreenEnabled
     }
@@ -30,6 +48,11 @@
     }
 
     fun setBypassEnabled(isBypassEnabled: Boolean) {
-        this.isBypassEnabled = isBypassEnabled
+        _isBypassEnabled.value = isBypassEnabled
     }
 }
+
+@Module
+interface FakeDeviceEntryRepositoryModule {
+    @Binds fun bindFake(fake: FakeDeviceEntryRepository): DeviceEntryRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt
new file mode 100644
index 0000000..95b5316
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 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.keyevent.data.repository
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeKeyEventRepository() : KeyEventRepository {
+    private val _isPowerButtonDown = MutableStateFlow(false)
+    override val isPowerButtonDown: Flow<Boolean> = _isPowerButtonDown.asStateFlow()
+
+    fun setPowerButtonDown(isDown: Boolean) {
+        _isPowerButtonDown.value = isDown
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
index 1a893f8..911eafa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
@@ -36,8 +36,6 @@
 import com.android.systemui.qs.QSSecurityFooterUtils
 import com.android.systemui.qs.footer.data.repository.ForegroundServicesRepository
 import com.android.systemui.qs.footer.data.repository.ForegroundServicesRepositoryImpl
-import com.android.systemui.qs.footer.data.repository.UserSwitcherRepository
-import com.android.systemui.qs.footer.data.repository.UserSwitcherRepositoryImpl
 import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
 import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractorImpl
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
@@ -51,9 +49,11 @@
 import com.android.systemui.statusbar.policy.SecurityController
 import com.android.systemui.statusbar.policy.UserInfoController
 import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.repository.UserSwitcherRepository
+import com.android.systemui.user.data.repository.UserSwitcherRepositoryImpl
 import com.android.systemui.user.domain.interactor.UserInteractor
 import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.settings.GlobalSettings
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.test.StandardTestDispatcher
@@ -69,8 +69,8 @@
     private val scheduler: TestCoroutineScheduler,
 ) {
     /** Enable or disable the user switcher in the settings. */
-    fun setUserSwitcherEnabled(settings: GlobalSettings, enabled: Boolean, userId: Int) {
-        settings.putBoolForUser(Settings.Global.USER_SWITCHER_ENABLED, enabled, userId)
+    fun setUserSwitcherEnabled(settings: GlobalSettings, enabled: Boolean) {
+        settings.putBool(Settings.Global.USER_SWITCHER_ENABLED, enabled)
 
         // The settings listener is processing messages on the bgHandler (usually backed by a
         // testableLooper in tests), so let's make sure we process the callback before continuing.
@@ -152,7 +152,7 @@
         userTracker: UserTracker = FakeUserTracker(),
         userSwitcherController: UserSwitcherController = mock(),
         userInfoController: UserInfoController = FakeUserInfoController(),
-        settings: GlobalSettings = FakeSettings(),
+        settings: GlobalSettings = FakeGlobalSettings(),
     ): UserSwitcherRepository {
         return UserSwitcherRepositoryImpl(
             context,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigTestBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigTestBuilder.kt
new file mode 100644
index 0000000..201926d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigTestBuilder.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.viewmodel
+
+import androidx.annotation.StringRes
+import com.android.internal.logging.InstanceId
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.qs.pipeline.shared.TileSpec
+
+object QSTileConfigTestBuilder {
+
+    fun build(configure: BuildingScope.() -> Unit = {}): QSTileConfig =
+        BuildingScope().apply(configure).build()
+
+    class BuildingScope {
+        var tileSpec: TileSpec = TileSpec.create("test_spec")
+        var tileIcon: Icon = Icon.Resource(0, ContentDescription.Resource(0))
+        @StringRes var tileLabel: Int = 0
+        var instanceId: InstanceId = InstanceId.fakeInstanceId(0)
+        var metricsSpec: String = tileSpec.spec
+        var policy: QSTilePolicy = QSTilePolicy.NoRestrictions
+
+        fun build() =
+            QSTileConfig(
+                tileSpec,
+                tileIcon,
+                tileLabel,
+                instanceId,
+                metricsSpec,
+                policy,
+            )
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 766f748..a4881bc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -80,7 +80,11 @@
 ) {
     val testDispatcher = StandardTestDispatcher()
     val testScope = TestScope(testDispatcher)
-    val featureFlags = FakeFeatureFlagsClassic().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
+    val featureFlags =
+        FakeFeatureFlagsClassic().apply {
+            set(Flags.FACE_AUTH_REFACTOR, false)
+            set(Flags.FULL_SCREEN_USER_SWITCHER, false)
+        }
     val sceneContainerFlags = FakeSceneContainerFlags().apply { enabled = true }
     val deviceEntryRepository: FakeDeviceEntryRepository by lazy { FakeDeviceEntryRepository() }
     val authenticationRepository: FakeAuthenticationRepository by lazy {
@@ -205,7 +209,7 @@
         return BouncerInteractor(
             applicationScope = applicationScope(),
             applicationContext = context,
-            repository = BouncerRepository(),
+            repository = BouncerRepository(featureFlags),
             deviceEntryInteractor = deviceEntryInteractor,
             authenticationInteractor = authenticationInteractor,
             sceneInteractor = sceneInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
index 1bec82b..e59f642 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
@@ -16,14 +16,18 @@
 package com.android.systemui.statusbar.data
 
 import com.android.systemui.statusbar.disableflags.data.FakeStatusBarDisableFlagsDataLayerModule
+import com.android.systemui.statusbar.notification.data.FakeStatusBarNotificationsDataLayerModule
 import com.android.systemui.statusbar.pipeline.data.FakeStatusBarPipelineDataLayerModule
+import com.android.systemui.statusbar.policy.data.FakeStatusBarPolicyDataLayerModule
 import dagger.Module
 
 @Module(
     includes =
         [
             FakeStatusBarDisableFlagsDataLayerModule::class,
+            FakeStatusBarNotificationsDataLayerModule::class,
             FakeStatusBarPipelineDataLayerModule::class,
+            FakeStatusBarPolicyDataLayerModule::class,
         ]
 )
 object FakeStatusBarDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt
new file mode 100644
index 0000000..788e3aa
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.data
+
+import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardStateRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeNotificationsKeyguardStateRepositoryModule::class])
+object FakeStatusBarNotificationsDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt
new file mode 100644
index 0000000..5d3cb4d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+@SysUISingleton
+class FakeNotificationsKeyguardViewStateRepository @Inject constructor() :
+    NotificationsKeyguardViewStateRepository {
+    private val _notificationsFullyHidden = MutableStateFlow(false)
+    override val areNotificationsFullyHidden: Flow<Boolean> = _notificationsFullyHidden
+
+    private val _isPulseExpanding = MutableStateFlow(false)
+    override val isPulseExpanding: Flow<Boolean> = _isPulseExpanding
+
+    fun setNotificationsFullyHidden(fullyHidden: Boolean) {
+        _notificationsFullyHidden.value = fullyHidden
+    }
+
+    fun setPulseExpanding(expanding: Boolean) {
+        _isPulseExpanding.value = expanding
+    }
+}
+
+@Module
+interface FakeNotificationsKeyguardStateRepositoryModule {
+    @Binds
+    fun bindFake(
+        fake: FakeNotificationsKeyguardViewStateRepository
+    ): NotificationsKeyguardViewStateRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
index 16a3268..23477d8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
@@ -1,9 +1,14 @@
 package com.android.systemui.statusbar.policy
 
 import android.content.res.Configuration
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
 
 /** Fake implementation of [ConfigurationController] for tests. */
-class FakeConfigurationController : ConfigurationController {
+@SysUISingleton
+class FakeConfigurationController @Inject constructor() : ConfigurationController {
 
     private var listeners = mutableListOf<ConfigurationController.ConfigurationListener>()
 
@@ -33,3 +38,8 @@
 
     override fun isLayoutRtl(): Boolean = false
 }
+
+@Module
+interface FakeConfigurationControllerModule {
+    @Binds fun bindFake(fake: FakeConfigurationController): ConfigurationController
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt
new file mode 100644
index 0000000..14bab84
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface FakeSplitShadeStateControllerModule {
+    @Binds fun bindFake(fake: ResourcesSplitShadeStateController): SplitShadeStateController
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt
new file mode 100644
index 0000000..5aece1b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy.data
+
+import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeDeviceProvisioningRepositoryModule::class])
+object FakeStatusBarPolicyDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt
new file mode 100644
index 0000000..3002299
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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.statusbar.policy.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+@SysUISingleton
+class FakeDeviceProvisioningRepository @Inject constructor() : DeviceProvisioningRepository {
+    private val _isDeviceProvisioned = MutableStateFlow(false)
+    override val isDeviceProvisioned: Flow<Boolean> = _isDeviceProvisioned
+    private val _isFactoryResetProtectionActive = MutableStateFlow(false)
+    override val isFactoryResetProtectionActive: Flow<Boolean> = _isFactoryResetProtectionActive
+    fun setDeviceProvisioned(isProvisioned: Boolean) {
+        _isDeviceProvisioned.value = isProvisioned
+    }
+    fun setFactoryResetProtectionActive(isActive: Boolean) {
+        _isFactoryResetProtectionActive.value = isActive
+    }
+}
+
+@Module
+interface FakeDeviceProvisioningRepositoryModule {
+    @Binds fun bindFake(fake: FakeDeviceProvisioningRepository): DeviceProvisioningRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt
index 5de05c2..1f48d94 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.util.concurrency
 
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.util.time.FakeSystemClock
 import dagger.Binds
@@ -22,14 +23,12 @@
 import dagger.Provides
 import java.util.concurrent.Executor
 
-@Module(includes = [FakeExecutorModule.Bindings::class])
-class FakeExecutorModule(
-    @get:Provides val clock: FakeSystemClock = FakeSystemClock(),
-) {
-    @get:Provides val executor = FakeExecutor(clock)
+@Module
+interface FakeExecutorModule {
+    @Binds @Main @SysUISingleton fun bindMainExecutor(executor: FakeExecutor): Executor
 
-    @Module
-    interface Bindings {
-        @Binds @Main fun bindMainExecutor(executor: FakeExecutor): Executor
+    companion object {
+        @Provides
+        fun provideFake(clock: FakeSystemClock) = FakeExecutor(clock)
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
new file mode 100644
index 0000000..db5eaff
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
@@ -0,0 +1,89 @@
+/*
+ * 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.systemui.util.settings;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class FakeGlobalSettings implements GlobalSettings {
+    private final Map<String, String> mValues = new HashMap<>();
+    private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>();
+
+    public static final Uri CONTENT_URI = Uri.parse("content://settings/fake_global");
+
+    public FakeGlobalSettings() {
+    }
+
+    @Override
+    public ContentResolver getContentResolver() {
+        return null;
+    }
+
+    @Override
+    public void registerContentObserver(Uri uri, boolean notifyDescendants,
+            ContentObserver settingsObserver) {
+        List<ContentObserver> observers;
+        mContentObserversAllUsers.putIfAbsent(uri.toString(), new ArrayList<>());
+        observers = mContentObserversAllUsers.get(uri.toString());
+        observers.add(settingsObserver);
+    }
+
+    @Override
+    public void unregisterContentObserver(ContentObserver settingsObserver) {
+        for (Map.Entry<String, List<ContentObserver>> entry :
+                mContentObserversAllUsers.entrySet()) {
+            entry.getValue().remove(settingsObserver);
+        }
+    }
+
+    @Override
+    public Uri getUriFor(String name) {
+        return Uri.withAppendedPath(CONTENT_URI, name);
+    }
+
+    @Override
+    public String getString(String name) {
+        return mValues.get(getUriFor(name).toString());
+    }
+
+    @Override
+    public boolean putString(String name, String value) {
+        return putString(name, value, null, false);
+    }
+
+    @Override
+    public boolean putString(@NonNull String name, @Nullable String value, @Nullable String tag,
+            boolean makeDefault) {
+        String key = getUriFor(name).toString();
+        mValues.put(key, value);
+
+        Uri uri = getUriFor(name);
+        for (ContentObserver observer :
+                mContentObserversAllUsers.getOrDefault(uri.toString(), new ArrayList<>())) {
+            observer.dispatchChange(false, List.of(uri), 0);
+        }
+        return true;
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
index 4b97316..a491886 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
@@ -23,6 +23,8 @@
 import android.os.UserHandle;
 import android.util.Pair;
 
+import androidx.annotation.NonNull;
+
 import com.android.systemui.settings.UserTracker;
 
 import java.util.ArrayList;
@@ -30,7 +32,7 @@
 import java.util.List;
 import java.util.Map;
 
-public class FakeSettings implements SecureSettings, GlobalSettings, SystemSettings {
+public class FakeSettings implements SecureSettings, SystemSettings {
     private final Map<SettingsKey, String> mValues = new HashMap<>();
     private final Map<SettingsKey, List<ContentObserver>> mContentObservers =
             new HashMap<>();
@@ -64,7 +66,7 @@
     }
 
     @Override
-    public void registerContentObserverForUser(Uri uri, boolean notifyDescendents,
+    public void registerContentObserverForUser(Uri uri, boolean notifyDescendants,
             ContentObserver settingsObserver, int userHandle) {
         List<ContentObserver> observers;
         if (userHandle == UserHandle.USER_ALL) {
@@ -147,7 +149,7 @@
     }
 
     @Override
-    public boolean putString(String name, String value, String tag, boolean makeDefault) {
+    public boolean putString(@NonNull String name, String value, String tag, boolean makeDefault) {
         return putString(name, value);
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockModule.kt
new file mode 100644
index 0000000..3e3d7cb
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockModule.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.util.time
+
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+
+@Module
+interface FakeSystemClockModule {
+    @Binds fun bindFake(fake: FakeSystemClock): SystemClock
+
+    companion object {
+        @Provides @SysUISingleton fun providesFake() = FakeSystemClock()
+    }
+}
diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp
index 155dc1a..18f78314 100644
--- a/packages/WallpaperBackup/Android.bp
+++ b/packages/WallpaperBackup/Android.bp
@@ -49,7 +49,7 @@
         "androidx.test.core",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     resource_dirs: ["test/res"],
     certificate: "platform",
diff --git a/packages/overlays/tests/Android.bp b/packages/overlays/tests/Android.bp
index b781602..0244c0f 100644
--- a/packages/overlays/tests/Android.bp
+++ b/packages/overlays/tests/Android.bp
@@ -34,7 +34,7 @@
         "androidx.test.rules",
         "androidx.test.espresso.core",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     dxflags: ["--multi-dex"],
 }
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index ced97cc..7ac7859 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -90,8 +90,14 @@
     // Make sound through the speaker.
     ALERT_BEEP = 2;
 
-    // Flash a notificaiton light.
+    // Flash a notification light.
     ALERT_BLINK = 4;
+
+    // Alert was attenuated by polite notif. feature.
+    ALERT_POLITE = 8;
+
+    // Alert was muted by polite notif. feature.
+    ALERT_MUTED = 16;
   }
 
   // Reasons that a notification might be dismissed.
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
new file mode 100644
index 0000000..91acc3d
--- /dev/null
+++ b/ravenwood/Android.bp
@@ -0,0 +1,33 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "ravenwood-annotations",
+    srcs: [
+        "annotations-src/**/*.java",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// File that contains the standard command line arguments to hoststubgen.
+filegroup {
+    name: "ravenwood-standard-options",
+    srcs: [
+        "ravenwood-standard-options.txt",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+java_library {
+    name: "ravenwood-annotations-lib",
+    srcs: [":ravenwood-annotations"],
+    sdk_version: "core_current",
+    host_supported: true,
+    visibility: ["//visibility:public"],
+}
diff --git a/ravenwood/OWNERS b/ravenwood/OWNERS
new file mode 100644
index 0000000..c06b3b9
--- /dev/null
+++ b/ravenwood/OWNERS
@@ -0,0 +1,3 @@
+jsharkey@google.com
+omakoto@google.com
+jaggies@google.com
diff --git a/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodClassLoadHook.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodClassLoadHook.java
new file mode 100644
index 0000000..be7b923
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodClassLoadHook.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 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.ravenwood.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Add this with a fully-specified method name (e.g. {@code "com.package.Class.methodName"})
+ * of a callback to get a callback at the class load time.
+ *
+ * The method must be {@code public static} with a single argument that takes
+ * {@link Class}.
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodClassLoadHook {
+    String value();
+}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodKeep.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodKeep.java
new file mode 100644
index 0000000..1644ffc
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodKeep.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 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.ravenwood.annotations;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * TODO: Javadoc
+ *
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodKeep {
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodNativeSubstitutionClass.java
similarity index 67%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java
rename to ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodNativeSubstitutionClass.java
index 3fff136..eb883e2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodNativeSubstitutionClass.java
@@ -13,19 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.ravenwood.annotations;
 
-package com.android.systemui;
+import static java.lang.annotation.ElementType.TYPE;
 
-import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Mark as tests for Robolectric pilot projects. The filter can better help grouping test results
- * that runs on CI
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * TODO: Javadoc
  */
-@Target({ElementType.METHOD, ElementType.TYPE})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface RoboPilotTest {
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodNativeSubstitutionClass {
+    String value();
 }
diff --git a/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodRemove.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodRemove.java
new file mode 100644
index 0000000..ffa1fa5
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodRemove.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 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.ravenwood.annotations;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * TODO: Javadoc
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodRemove {
+}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodSubstitute.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodSubstitute.java
new file mode 100644
index 0000000..6d747da
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodSubstitute.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 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.ravenwood.annotations;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * TODO: Javadoc
+ */
+@Target({METHOD})
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodSubstitute {
+    // TODO We should add "_host" as default. We're not doing it yet, because extractign the default
+    // value with ASM doesn't seem trivial. (? not sure.)
+    String suffix();
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodThrow.java
similarity index 63%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java
copy to ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodThrow.java
index 3fff136..a329d84 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodThrow.java
@@ -13,19 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.ravenwood.annotations;
 
-package com.android.systemui;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
 
-import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Mark as tests for Robolectric pilot projects. The filter can better help grouping test results
- * that runs on CI
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * TODO: Javadoc
+ * TODO: Create "whole-class-throw"?
  */
-@Target({ElementType.METHOD, ElementType.TYPE})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface RoboPilotTest {
+@Target({METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodThrow {
 }
diff --git a/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodWholeClassKeep.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodWholeClassKeep.java
new file mode 100644
index 0000000..ae6f42d
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodWholeClassKeep.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 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.ravenwood.annotations;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * TODO: Javadoc
+ * TODO: Create "whole-class-throw"?
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodWholeClassKeep {
+}
diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/ravenwood-standard-options.txt
new file mode 100644
index 0000000..6e1384f
--- /dev/null
+++ b/ravenwood/ravenwood-standard-options.txt
@@ -0,0 +1,37 @@
+# File containing standard options to HostStubGen for Ravenwood
+
+--debug
+
+# Keep all classes / methods / fields, but make the methods throw.
+--default-throw
+
+# Uncomment below lines to enable each feature.
+# --enable-non-stub-method-check
+
+#--default-method-call-hook
+#    com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+#--default-class-load-hook
+#    com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+
+# Standard annotations.
+# Note, each line is a single argument, so we need newlines after each `--xxx-annotation`.
+--keep-annotation
+    android.ravenwood.annotations.RavenwoodKeep
+
+--keep-class-annotation
+    android.ravenwood.annotations.RavenwoodWholeClassKeep
+
+--throw-annotation
+    android.ravenwood.annotations.RavenwoodThrow
+
+--remove-annotation
+    android.ravenwood.annotations.RavenwoodRemove
+
+--substitute-annotation
+    android.ravenwood.annotations.RavenwoodSubstitute
+
+--native-substitute-annotation
+    android.ravenwood.annotations.RavenwoodNativeSubstitutionClass
+
+--class-load-hook-annotation
+    android.ravenwood.annotations.RavenwoodClassLoadHook
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 11189cf..10ac2eb 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -34,3 +34,17 @@
     description: "Calls WMS.addWindowToken without holding A11yManagerService#mLock"
     bug: "297972548"
 }
+
+flag {
+    name: "pinch_zoom_zero_min_span"
+    namespace: "accessibility"
+    description: "Whether to set min span of ScaleGestureDetector to zero."
+    bug: "295327792"
+}
+
+flag {
+    name: "deprecate_package_list_observer"
+    namespace: "accessibility"
+    description: "Stops using the deprecated PackageListObserver."
+    bug: "304561459"
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 60d4ee6..aa6d800 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -841,32 +841,32 @@
         // package changes
         monitor.register(mContext, null,  UserHandle.ALL, true);
 
-        // Register an additional observer for new packages using PackageManagerInternal, which
-        // generally notifies observers much sooner than the BroadcastReceiver-based PackageMonitor.
-        final PackageManagerInternal pm = LocalServices.getService(
-                PackageManagerInternal.class);
-        if (pm != null) {
-            pm.getPackageList(new PackageManagerInternal.PackageListObserver() {
-                @Override
-                public void onPackageAdded(String packageName, int uid) {
-                    final int userId = UserHandle.getUserId(uid);
-                    synchronized (mLock) {
-                        if (userId == mCurrentUserId) {
-                            onSomePackagesChangedLocked();
+        if (!Flags.deprecatePackageListObserver()) {
+            final PackageManagerInternal pm = LocalServices.getService(
+                    PackageManagerInternal.class);
+            if (pm != null) {
+                pm.getPackageList(new PackageManagerInternal.PackageListObserver() {
+                    @Override
+                    public void onPackageAdded(String packageName, int uid) {
+                        final int userId = UserHandle.getUserId(uid);
+                        synchronized (mLock) {
+                            if (userId == mCurrentUserId) {
+                                onSomePackagesChangedLocked();
+                            }
                         }
                     }
-                }
 
-                @Override
-                public void onPackageRemoved(String packageName, int uid) {
-                    final int userId = UserHandle.getUserId(uid);
-                    synchronized (mLock) {
-                        if (userId == mCurrentUserId) {
-                            onPackageRemovedLocked(packageName);
+                    @Override
+                    public void onPackageRemoved(String packageName, int uid) {
+                        final int userId = UserHandle.getUserId(uid);
+                        synchronized (mLock) {
+                            if (userId == mCurrentUserId) {
+                                onPackageRemovedLocked(packageName);
+                            }
                         }
                     }
-                }
-            });
+                });
+            }
         }
 
         // user change and unlock
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index 30b9d0b..01064ac 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -873,7 +873,7 @@
 
                         transitionToDelegatingStateAndClear();
 
-                    } else if (mDetectTripleTap
+                    } else if (mDetectSingleFingerTripleTap
                             // If activated, delay an ACTION_DOWN for mMultiTapMaxDelay
                             // to ensure reachability of
                             // STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
@@ -989,7 +989,7 @@
             // Shortcut acts as the 2 initial taps
             if (mShortcutTriggered) return tapCount() + 2 >= numTaps;
 
-            final boolean multitapTriggered = mDetectTripleTap
+            final boolean multitapTriggered = mDetectSingleFingerTripleTap
                     && tapCount() >= numTaps
                     && isMultiTap(mPreLastDown, mLastDown)
                     && isMultiTap(mPreLastUp, mLastUp);
@@ -1205,7 +1205,7 @@
          * @return true if tap is out of distance slop
          */
         boolean isTapOutOfDistanceSlop() {
-            if (!mDetectTripleTap) return false;
+            if (!mDetectSingleFingerTripleTap) return false;
             if (mPreLastDown == null || mLastDown == null) {
                 return false;
             }
@@ -1282,7 +1282,7 @@
                 + ", mMagnifiedInteractionState=" + mPanningScalingState
                 + ", mViewportDraggingState=" + mViewportDraggingState
                 + ", mSinglePanningState=" + mSinglePanningState
-                + ", mDetectTripleTap=" + mDetectTripleTap
+                + ", mDetectSingleFingerTripleTap=" + mDetectSingleFingerTripleTap
                 + ", mDetectShortcutTrigger=" + mDetectShortcutTrigger
                 + ", mCurrentState=" + State.nameOf(mCurrentState)
                 + ", mPreviousState=" + State.nameOf(mPreviousState)
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
index 2894693..8476a5e 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
@@ -57,11 +57,11 @@
     protected final boolean mDetectShortcutTrigger;
 
     /**
-     * {@code true} if this detector should detect and respond to triple-tap
+     * {@code true} if this detector should detect and respond to single-finger triple-tap
      * gestures for engaging and disengaging magnification,
      * {@code false} if it should ignore such gestures
      */
-    protected final boolean mDetectTripleTap;
+    protected final boolean mDetectSingleFingerTripleTap;
 
     /** Callback interface to report that magnification is interactive with a user. */
     public interface Callback {
@@ -85,12 +85,12 @@
     private final AccessibilityTraceManager mTrace;
     protected final Callback mCallback;
 
-    protected MagnificationGestureHandler(int displayId, boolean detectTripleTap,
+    protected MagnificationGestureHandler(int displayId, boolean detectSingleFingerTripleTap,
             boolean detectShortcutTrigger,
             AccessibilityTraceManager trace,
             @NonNull Callback callback) {
         mDisplayId = displayId;
-        mDetectTripleTap = detectTripleTap;
+        mDetectSingleFingerTripleTap = detectSingleFingerTripleTap;
         mDetectShortcutTrigger = detectShortcutTrigger;
         mTrace = trace;
         mCallback = callback;
@@ -128,7 +128,7 @@
     }
 
     private boolean shouldDispatchTransformedEvent(MotionEvent event) {
-        if ((!mDetectTripleTap && !mDetectShortcutTrigger) || !event.isFromSource(
+        if ((!mDetectSingleFingerTripleTap && !mDetectShortcutTrigger) || !event.isFromSource(
                 SOURCE_TOUCHSCREEN)) {
             return true;
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java
index c5495d9..9455628 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java
@@ -28,8 +28,10 @@
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
+import android.view.ViewConfiguration;
 
 import com.android.internal.R;
+import com.android.server.accessibility.Flags;
 
 /**
  * Handles the behavior while receiving scaling and panning gestures if it's enabled.
@@ -70,7 +72,13 @@
         mMaxScale = maxScale;
         mMinScale = minScale;
         mBlockScroll = blockScroll;
-        mScaleGestureDetector = new ScaleGestureDetector(context, this, Handler.getMain());
+        if (Flags.pinchZoomZeroMinSpan()) {
+            mScaleGestureDetector = new ScaleGestureDetector(context,
+                    ViewConfiguration.get(context).getScaledTouchSlop() * 2,
+                    /* minSpan= */ 0, Handler.getMain(), this);
+        } else {
+            mScaleGestureDetector = new ScaleGestureDetector(context, this, Handler.getMain());
+        }
         mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain());
         mScaleGestureDetector.setQuickScaleEnabled(false);
         mMagnificationDelegate = magnificationDelegate;
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 c58e9a6..2d9dcb9 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -111,7 +111,7 @@
                 (event, rawEvent, policyFlags) -> dispatchTransformedEvent(event, rawEvent,
                         policyFlags));
         mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate);
-        mDetectingState = new DetectingState(context, mDetectTripleTap);
+        mDetectingState = new DetectingState(context);
         mViewportDraggingState = new ViewportDraggingState();
         mObservePanningScalingState = new PanningScalingGestureState(
                 new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true,
@@ -448,22 +448,14 @@
 
         private final MagnificationGesturesObserver mGesturesObserver;
 
-        /**
-         * {@code true} if this detector should detect and respond to triple-tap
-         * gestures for engaging and disengaging magnification,
-         * {@code false} if it should ignore such gestures
-         */
-        private final boolean mDetectTripleTap;
-
-        DetectingState(@UiContext Context context, boolean detectTripleTap) {
-            mDetectTripleTap = detectTripleTap;
-            final MultiTap multiTap = new MultiTap(context, mDetectTripleTap ? 3 : 1,
-                    mDetectTripleTap
+        DetectingState(@UiContext Context context) {
+            final MultiTap multiTap = new MultiTap(context, mDetectSingleFingerTripleTap ? 3 : 1,
+                    mDetectSingleFingerTripleTap
                             ? MagnificationGestureMatcher.GESTURE_TRIPLE_TAP
                             : MagnificationGestureMatcher.GESTURE_SINGLE_TAP, null);
             final MultiTapAndHold multiTapAndHold = new MultiTapAndHold(context,
-                    mDetectTripleTap ? 3 : 1,
-                    mDetectTripleTap
+                    mDetectSingleFingerTripleTap ? 3 : 1,
+                    mDetectSingleFingerTripleTap
                             ? MagnificationGestureMatcher.GESTURE_TRIPLE_TAP_AND_HOLD
                             : MagnificationGestureMatcher.GESTURE_SINGLE_TAP_AND_HOLD, null);
             mGesturesObserver = new MagnificationGesturesObserver(this,
@@ -488,7 +480,7 @@
         @Override
         public boolean shouldStopDetection(MotionEvent motionEvent) {
             return !mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId)
-                    && !mDetectTripleTap;
+                    && !mDetectSingleFingerTripleTap;
         }
 
         @Override
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 7e09b5e..258820a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -24,6 +24,7 @@
 
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -1660,8 +1661,21 @@
         synchronized (mLock) {
             ensureGroupStateLoadedLocked(userId);
 
+            final String pkg = componentName.getPackageName();
+            final ProviderId id;
+            if (!mPackageManagerInternal.isSameApp(pkg, callingUid, userId)) {
+                // If the calling process is requesting to pin appwidgets from another process,
+                // check if the calling process has the necessary permission.
+                if (!injectHasAccessWidgetsPermission(Binder.getCallingPid(), callingUid)) {
+                    return false;
+                }
+                id = new ProviderId(mPackageManagerInternal.getPackageUid(
+                        pkg, 0 /* flags */, userId), componentName);
+            } else {
+                id = new ProviderId(callingUid, componentName);
+            }
             // Look for the widget associated with the caller.
-            Provider provider = lookupProviderLocked(new ProviderId(callingUid, componentName));
+            Provider provider = lookupProviderLocked(id);
             if (provider == null || provider.zombie) {
                 return false;
             }
@@ -1675,6 +1689,14 @@
                 .requestPinAppWidget(callingPackage, info, extras, resultSender, userId);
     }
 
+    /**
+     * Returns true if the caller has the proper permission to access app widgets.
+     */
+    private boolean injectHasAccessWidgetsPermission(int callingPid, int callingUid) {
+        return mContext.checkPermission(Manifest.permission.CLEAR_APP_USER_DATA,
+                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+    }
+
     @Override
     public ParceledListSlice<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter,
             int profileId, String packageName) {
@@ -4131,7 +4153,7 @@
             return false;
         }
 
-        @GuardedBy("mLock")
+        @GuardedBy("AppWidgetServiceImpl.mLock")
         public AppWidgetProviderInfo getInfoLocked(Context context) {
             if (!mInfoParsed) {
                 // parse
@@ -4159,18 +4181,18 @@
          * be completely parsed and only contain placeHolder information like
          * {@link AppWidgetProviderInfo#providerInfo}
          */
-        @GuardedBy("mLock")
+        @GuardedBy("AppWidgetServiceImpl.mLock")
         public AppWidgetProviderInfo getPartialInfoLocked() {
             return info;
         }
 
-        @GuardedBy("mLock")
+        @GuardedBy("AppWidgetServiceImpl.mLock")
         public void setPartialInfoLocked(AppWidgetProviderInfo info) {
             this.info = info;
             mInfoParsed = false;
         }
 
-        @GuardedBy("mLock")
+        @GuardedBy("AppWidgetServiceImpl.mLock")
         public void setInfoLocked(AppWidgetProviderInfo info) {
             this.info = info;
             mInfoParsed = true;
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
index d43a219..eb23f2f 100644
--- a/services/autofill/Android.bp
+++ b/services/autofill/Android.bp
@@ -19,19 +19,4 @@
     defaults: ["platform_service_defaults"],
     srcs: [":services.autofill-sources"],
     libs: ["services.core"],
-    static_libs: ["autofill_flags_java_lib"],
-}
-
-aconfig_declarations {
-    name: "autofill_flags",
-    package: "android.service.autofill",
-    srcs: [
-        "bugfixes.aconfig",
-        "features.aconfig",
-    ],
-}
-
-java_aconfig_library {
-    name: "autofill_flags_java_lib",
-    aconfig_declarations: "autofill_flags",
 }
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index ef23754..b37bbd6 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -5,4 +5,18 @@
   namespace: "autofill"
   description: "Test flag "
   bug: "297380045"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "fill_fields_from_current_session_only"
+  namespace: "autofill"
+  description: "Only fill autofill fields that are part of the current session."
+  bug: "270722825"
+}
+
+flag {
+  name: "relayout"
+  namespace: "autofill"
+  description: "Mitigation for relayout issue"
+  bug: "294330426"
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index c7b53c5..72242d2 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -58,6 +58,7 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.autofill.FillEventHistory;
+import android.service.autofill.Flags;
 import android.service.autofill.UserData;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
@@ -226,6 +227,12 @@
     @GuardedBy("mFlagLock")
     private int mMaxInputLengthForAutofill;
 
+    @GuardedBy("mFlagLock")
+    private boolean mAutofillCredmanIntegrationEnabled;
+
+    @GuardedBy("mFlagLock")
+    private boolean mIsFillFieldsFromCurrentSessionOnly;
+
     // Default flag values for Autofill PCC
 
     private static final String DEFAULT_PCC_FEATURE_PROVIDER_HINTS = "";
@@ -701,12 +708,16 @@
                     DeviceConfig.NAMESPACE_AUTOFILL,
                     AutofillFeatureFlags.DEVICE_CONFIG_MAX_INPUT_LENGTH_FOR_AUTOFILL,
                     AutofillFeatureFlags.DEFAULT_MAX_INPUT_LENGTH_FOR_AUTOFILL);
+            mAutofillCredmanIntegrationEnabled = Flags.autofillCredmanIntegration();
+            mIsFillFieldsFromCurrentSessionOnly = Flags.fillFieldsFromCurrentSessionOnly();
             if (verbose) {
                 Slog.v(mTag, "setDeviceConfigProperties() for PCC: "
                         + "mPccClassificationEnabled=" + mPccClassificationEnabled
                         + ", mPccPreferProviderOverPcc=" + mPccPreferProviderOverPcc
                         + ", mPccUseFallbackDetection=" + mPccUseFallbackDetection
-                        + ", mPccProviderHints=" + mPccProviderHints);
+                        + ", mPccProviderHints=" + mPccProviderHints
+                        + ", mAutofillCredmanIntegrationEnabled="
+                        + mAutofillCredmanIntegrationEnabled);
             }
         }
     }
@@ -965,6 +976,15 @@
     }
 
     /**
+     * Whether the Autofill-Credman integration feature flag is enabled.
+     */
+    public boolean isAutofillCredmanIntegrationEnabled() {
+        synchronized (mFlagLock) {
+            return mAutofillCredmanIntegrationEnabled;
+        }
+    }
+
+    /**
      * Whether the Autofill Provider shouldbe preferred over PCC results for selecting datasets.
      */
     public boolean preferProviderOverPcc() {
@@ -1004,6 +1024,15 @@
         }
     }
 
+    /**
+     * Return if autofill should only fill in fields from current session.
+     */
+    public boolean getIsFillFieldsFromCurrentSessionOnly() {
+        synchronized (mFlagLock) {
+            return mIsFillFieldsFromCurrentSessionOnly;
+        }
+    }
+
     @Nullable
     @VisibleForTesting
     static Map<String, String[]> getAllowedCompatModePackages(String setting) {
@@ -2096,6 +2125,9 @@
                         pw.print(";");
                         pw.print("mPccProviderHints=");
                         pw.println(mPccProviderHints);
+                        pw.print(";");
+                        pw.print("mAutofillCredmanIntegrationEnabled=");
+                        pw.println(mAutofillCredmanIntegrationEnabled);
                     }
                     // Dump per-user services
                     dumpLocked("", pw);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 5b8bdd5..518b81f 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -19,6 +19,7 @@
 import static android.service.autofill.FillEventHistory.Event.NO_SAVE_UI_REASON_NONE;
 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.service.autofill.FillRequest.FLAG_SCREEN_HAS_CREDMAN_FIELD;
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED;
 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
@@ -103,6 +104,10 @@
         extends AbstractPerUserSystemService<AutofillManagerServiceImpl, AutofillManagerService> {
 
     private static final String TAG = "AutofillManagerServiceImpl";
+
+    private static final ComponentName CREDMAN_SERVICE_COMPONENT_NAME =
+            new ComponentName("com.android.credentialmanager",
+                    "com.android.credentialmanager.autofill.CredentialAutofillService");
     private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
 
     /** Minimum interval to prune abandoned sessions */
@@ -532,9 +537,16 @@
 
         assertCallerLocked(clientActivity, compatMode);
 
-        // It's null when the session is just for augmented autofill
-        final ComponentName serviceComponentName = mInfo == null ? null
+        ComponentName serviceComponentName = mInfo == null ? null
                 : mInfo.getServiceInfo().getComponentName();
+
+        if (isAutofillCredmanIntegrationEnabled()
+                && ((flags & FLAG_SCREEN_HAS_CREDMAN_FIELD) != 0)) {
+            // Hardcode to credential manager proxy service
+            Slog.i(TAG, "Routing to CredentialAutofillService");
+            serviceComponentName = CREDMAN_SERVICE_COMPONENT_NAME;
+        }
+
         final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
                 sessionId, taskId, clientUid, clientActivityToken, clientCallback, hasCallback,
                 mUiLatencyHistory, mWtfHistory, serviceComponentName,
@@ -1747,6 +1759,10 @@
         }
     }
 
+    public boolean isAutofillCredmanIntegrationEnabled() {
+        return mMaster.isAutofillCredmanIntegrationEnabled();
+    }
+
     /**
      * Called when the {@link AutofillManagerService#mFieldClassificationResolver}
      * changed (among other places).
diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
deleted file mode 100644
index 715697d..0000000
--- a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
+++ /dev/null
@@ -1,293 +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.autofill;
-
-import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
-
-import static com.android.server.autofill.Helper.sVerbose;
-
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.AppGlobals;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.ICancellationSignal;
-import android.os.RemoteException;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.service.autofill.IFillCallback;
-import android.service.autofill.SaveInfo;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Slog;
-import android.view.autofill.AutofillId;
-import android.view.autofill.IAutoFillManagerClient;
-import android.view.inputmethod.InlineSuggestionsRequest;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
-
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Maintains a client suggestions session with the
- * {@link android.view.autofill.AutofillRequestCallback} through the {@link IAutoFillManagerClient}.
- *
- */
-final class ClientSuggestionsSession {
-
-    private static final String TAG = "ClientSuggestionsSession";
-    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 15 * DateUtils.SECOND_IN_MILLIS;
-
-    private final int mSessionId;
-    private final IAutoFillManagerClient mClient;
-    private final Handler mHandler;
-    private final ComponentName mComponentName;
-
-    private final RemoteFillService.FillServiceCallbacks mCallbacks;
-
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    private AndroidFuture<FillResponse> mPendingFillRequest;
-    @GuardedBy("mLock")
-    private int mPendingFillRequestId = INVALID_REQUEST_ID;
-
-    ClientSuggestionsSession(int sessionId, IAutoFillManagerClient client, Handler handler,
-            ComponentName componentName, RemoteFillService.FillServiceCallbacks callbacks) {
-        mSessionId = sessionId;
-        mClient = client;
-        mHandler = handler;
-        mComponentName = componentName;
-        mCallbacks = callbacks;
-    }
-
-    void onFillRequest(int requestId, InlineSuggestionsRequest inlineRequest, int flags) {
-        final AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
-        final AtomicReference<AndroidFuture<FillResponse>> futureRef = new AtomicReference<>();
-        final AndroidFuture<FillResponse> fillRequest = new AndroidFuture<>();
-
-        mHandler.post(() -> {
-            if (sVerbose) {
-                Slog.v(TAG, "calling onFillRequest() for id=" + requestId);
-            }
-
-            try {
-                mClient.requestFillFromClient(requestId, inlineRequest,
-                        new FillCallbackImpl(fillRequest, futureRef, cancellationSink));
-            } catch (RemoteException e) {
-                fillRequest.completeExceptionally(e);
-            }
-        });
-
-        fillRequest.orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
-        futureRef.set(fillRequest);
-
-        synchronized (mLock) {
-            mPendingFillRequest = fillRequest;
-            mPendingFillRequestId = requestId;
-        }
-
-        fillRequest.whenComplete((res, err) -> mHandler.post(() -> {
-            synchronized (mLock) {
-                mPendingFillRequest = null;
-                mPendingFillRequestId = INVALID_REQUEST_ID;
-            }
-            if (err == null) {
-                processAutofillId(res);
-                mCallbacks.onFillRequestSuccess(requestId, res,
-                        mComponentName.getPackageName(), flags);
-            } else {
-                Slog.e(TAG, "Error calling on  client fill request", err);
-                if (err instanceof TimeoutException) {
-                    dispatchCancellationSignal(cancellationSink.get());
-                    mCallbacks.onFillRequestTimeout(requestId);
-                } else if (err instanceof CancellationException) {
-                    dispatchCancellationSignal(cancellationSink.get());
-                } else {
-                    mCallbacks.onFillRequestFailure(requestId, err.getMessage());
-                }
-            }
-        }));
-    }
-
-    /**
-     * Gets the application info for the component.
-     */
-    @Nullable
-    static ApplicationInfo getAppInfo(ComponentName comp, @UserIdInt int userId) {
-        try {
-            ApplicationInfo si = AppGlobals.getPackageManager().getApplicationInfo(
-                    comp.getPackageName(),
-                    PackageManager.GET_META_DATA,
-                    userId);
-            if (si != null) {
-                return si;
-            }
-        } catch (RemoteException e) {
-        }
-        return null;
-    }
-
-    /**
-     * Gets the user-visible name of the application.
-     */
-    @Nullable
-    @GuardedBy("mLock")
-    static CharSequence getAppLabelLocked(Context context, ApplicationInfo appInfo) {
-        return appInfo == null ? null : appInfo.loadSafeLabel(
-                context.getPackageManager(), 0 /* do not ellipsize */,
-                TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
-    }
-
-    /**
-     * Gets the user-visible icon of the application.
-     */
-    @Nullable
-    @GuardedBy("mLock")
-    static Drawable getAppIconLocked(Context context, ApplicationInfo appInfo) {
-        return appInfo == null ? null : appInfo.loadIcon(context.getPackageManager());
-    }
-
-    int cancelCurrentRequest() {
-        synchronized (mLock) {
-            return mPendingFillRequest != null && mPendingFillRequest.cancel(false)
-                    ? mPendingFillRequestId
-                    : INVALID_REQUEST_ID;
-        }
-    }
-
-    /**
-     * The {@link AutofillId} which the client gets from its view is not contain the session id,
-     * but Autofill framework is using the {@link AutofillId} with a session id. So before using
-     * those ids in the Autofill framework, applies the current session id.
-     *
-     * @param res which response need to apply for a session id
-     */
-    private void processAutofillId(FillResponse res) {
-        if (res == null) {
-            return;
-        }
-
-        final List<Dataset> datasets = res.getDatasets();
-        if (datasets != null && !datasets.isEmpty()) {
-            for (int i = 0; i < datasets.size(); i++) {
-                final Dataset dataset = datasets.get(i);
-                if (dataset != null) {
-                    applySessionId(dataset.getFieldIds());
-                }
-            }
-        }
-
-        final SaveInfo saveInfo = res.getSaveInfo();
-        if (saveInfo != null) {
-            applySessionId(saveInfo.getOptionalIds());
-            applySessionId(saveInfo.getRequiredIds());
-            applySessionId(saveInfo.getSanitizerValues());
-            applySessionId(saveInfo.getTriggerId());
-        }
-    }
-
-    private void applySessionId(List<AutofillId> ids) {
-        if (ids == null || ids.isEmpty()) {
-            return;
-        }
-
-        for (int i = 0; i < ids.size(); i++) {
-            applySessionId(ids.get(i));
-        }
-    }
-
-    private void applySessionId(AutofillId[][] ids) {
-        if (ids == null) {
-            return;
-        }
-        for (int i = 0; i < ids.length; i++) {
-            applySessionId(ids[i]);
-        }
-    }
-
-    private void applySessionId(AutofillId[] ids) {
-        if (ids == null) {
-            return;
-        }
-        for (int i = 0; i < ids.length; i++) {
-            applySessionId(ids[i]);
-        }
-    }
-
-    private void applySessionId(AutofillId id) {
-        if (id == null) {
-            return;
-        }
-        id.setSessionId(mSessionId);
-    }
-
-    private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) {
-        if (signal == null) {
-            return;
-        }
-        try {
-            signal.cancel();
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Error requesting a cancellation", e);
-        }
-    }
-
-    private class FillCallbackImpl extends IFillCallback.Stub {
-        final AndroidFuture<FillResponse> mFillRequest;
-        final AtomicReference<AndroidFuture<FillResponse>> mFutureRef;
-        final AtomicReference<ICancellationSignal> mCancellationSink;
-
-        FillCallbackImpl(AndroidFuture<FillResponse> fillRequest,
-                AtomicReference<AndroidFuture<FillResponse>> futureRef,
-                AtomicReference<ICancellationSignal> cancellationSink) {
-            mFillRequest = fillRequest;
-            mFutureRef = futureRef;
-            mCancellationSink = cancellationSink;
-        }
-
-        @Override
-        public void onCancellable(ICancellationSignal cancellation) {
-            AndroidFuture<FillResponse> future = mFutureRef.get();
-            if (future != null && future.isCancelled()) {
-                dispatchCancellationSignal(cancellation);
-            } else {
-                mCancellationSink.set(cancellation);
-            }
-        }
-
-        @Override
-        public void onSuccess(FillResponse response) {
-            mFillRequest.complete(response);
-        }
-
-        @Override
-        public void onFailure(int requestId, CharSequence message) {
-            String errorMessage = message == null ? "" : String.valueOf(message);
-            mFillRequest.completeExceptionally(
-                    new RuntimeException(errorMessage));
-        }
-    }
-}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0220dec..07e9c50 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -16,7 +16,6 @@
 
 package com.android.server.autofill;
 
-import static android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS;
 import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
 import static android.service.autofill.AutofillService.EXTRA_FILL_RESPONSE;
 import static android.service.autofill.Dataset.PICK_REASON_NO_PCC;
@@ -44,7 +43,6 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 import static android.view.autofill.AutofillManager.COMMIT_REASON_SESSION_DESTROYED;
 import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN;
-import static android.view.autofill.AutofillManager.FLAG_ENABLED_CLIENT_SUGGESTIONS;
 import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
 import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
 
@@ -110,8 +108,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
@@ -481,9 +477,6 @@
      */
     private final PccAssistDataReceiverImpl mPccAssistReceiver = new PccAssistDataReceiverImpl();
 
-    @Nullable
-    private ClientSuggestionsSession mClientSuggestionsSession;
-
     private final ClassificationState mClassificationState = new ClassificationState();
 
     // TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
@@ -625,9 +618,6 @@
         /** Whether the current {@link FillResponse} is expired. */
         private boolean mExpiredResponse;
 
-        /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */
-        private boolean mClientSuggestionsEnabled;
-
         /** Whether the fill dialog UI is disabled. */
         private boolean mFillDialogDisabled;
 
@@ -673,19 +663,13 @@
                 }
                 mWaitForInlineRequest = inlineSuggestionsRequest != null;
                 mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
-                maybeRequestFillFromServiceLocked();
+                maybeRequestFillLocked();
                 viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
             }
         }
 
-        void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
-            mPendingFillRequest = null;
-            mWaitForInlineRequest = inlineRequest != null;
-            mPendingInlineSuggestionsRequest = inlineRequest;
-        }
-
         @GuardedBy("mLock")
-        void maybeRequestFillFromServiceLocked() {
+        void maybeRequestFillLocked() {
             if (mPendingFillRequest == null) {
                 return;
             }
@@ -696,15 +680,13 @@
                     return;
                 }
 
-                if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
-                    mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
-                            mPendingFillRequest.getFillContexts(),
-                            mPendingFillRequest.getHints(),
-                            mPendingFillRequest.getClientState(),
-                            mPendingFillRequest.getFlags(),
-                            mPendingInlineSuggestionsRequest,
-                            mPendingFillRequest.getDelayedFillIntentSender());
-                }
+                mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+                        mPendingFillRequest.getFillContexts(),
+                        mPendingFillRequest.getHints(),
+                        mPendingFillRequest.getClientState(),
+                        mPendingFillRequest.getFlags(),
+                        mPendingInlineSuggestionsRequest,
+                        mPendingFillRequest.getDelayedFillIntentSender());
             }
             mLastFillRequest = mPendingFillRequest;
 
@@ -826,7 +808,7 @@
                             : mDelayedFillPendingIntent.getIntentSender());
 
                 mPendingFillRequest = request;
-                maybeRequestFillFromServiceLocked();
+                maybeRequestFillLocked();
             }
 
             if (mActivityToken != null) {
@@ -1152,39 +1134,30 @@
     }
 
     /**
-     * Cancels the last request sent to the {@link #mRemoteFillService} or the
-     * {@link #mClientSuggestionsSession}.
+     * Cancels the last request sent to the {@link #mRemoteFillService}.
      */
     @GuardedBy("mLock")
     private void cancelCurrentRequestLocked() {
-        if (mRemoteFillService == null && mClientSuggestionsSession == null) {
-            wtf(null, "cancelCurrentRequestLocked() called without a remote service or a "
-                    + "client suggestions session.  mForAugmentedAutofillOnly: %s",
-                    mSessionFlags.mAugmentedAutofillOnly);
+        if (mRemoteFillService == null) {
+            wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
+                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
             return;
         }
+        final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
 
-        if (mRemoteFillService != null) {
-            final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
+        // Remove the FillContext as there will never be a response for the service
+        if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
+            final int numContexts = mContexts.size();
 
-            // Remove the FillContext as there will never be a response for the service
-            if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
-                final int numContexts = mContexts.size();
-
-                // It is most likely the last context, hence search backwards
-                for (int i = numContexts - 1; i >= 0; i--) {
-                    if (mContexts.get(i).getRequestId() == canceledRequest) {
-                        if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
-                        mContexts.remove(i);
-                        break;
-                    }
+            // It is most likely the last context, hence search backwards
+            for (int i = numContexts - 1; i >= 0; i--) {
+                if (mContexts.get(i).getRequestId() == canceledRequest) {
+                    if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
+                    mContexts.remove(i);
+                    break;
                 }
             }
         }
-
-        if (mClientSuggestionsSession != null) {
-            mClientSuggestionsSession.cancelCurrentRequest();
-        }
     }
 
     private boolean isViewFocusedLocked(int flags) {
@@ -1280,30 +1253,16 @@
             requestAssistStructureForPccLocked(flags | FLAG_PCC_DETECTION);
         }
 
-        // Only ask IME to create inline suggestions request when
-        // 1. Autofill provider supports it or client enabled client suggestions.
-        // 2. The render service is available.
-        // 3. The view is focused. (The view may not be focused if the autofill is triggered
-        //    manually.)
+        // Only ask IME to create inline suggestions request if Autofill provider supports it and
+        // the render service is available except the autofill is triggered manually and the view
+        // is also not focused.
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
-        if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
-                && remoteRenderService != null
-                && (isViewFocusedLocked(flags) || (isRequestSupportFillDialog(flags)))) {
-            final Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
-            if (mSessionFlags.mClientSuggestionsEnabled) {
-                final int finalRequestId = requestId;
-                inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> {
-                    // Using client suggestions
-                    synchronized (mLock) {
-                        onClientFillRequestLocked(finalRequestId, inlineSuggestionsRequest);
-                    }
-                    viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
-                };
-            } else {
-                inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked(
-                        viewState, /* isInlineRequest= */ true);
-            }
+        if (mSessionFlags.mInlineSupportedByService && remoteRenderService != null
+            && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
+            Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
+                mAssistReceiver.newAutofillRequestLocked(viewState,
+                    /* isInlineRequest= */ true);
             if (inlineSuggestionsRequestConsumer != null) {
                 final int requestIdCopy = requestId;
                 final AutofillId focusedId = mCurrentViewId;
@@ -1323,18 +1282,10 @@
                         inlineSuggestionRendorInfoCallback);
                 viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
             }
-        } else if (mSessionFlags.mClientSuggestionsEnabled) {
-            // Request client suggestions for the dropdown mode
-            onClientFillRequestLocked(requestId, null);
         } else {
             mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false);
         }
 
-        if (mSessionFlags.mClientSuggestionsEnabled) {
-            // Using client suggestions, unnecessary request AssistStructure
-            return;
-        }
-
         // Now request the assist structure data.
         requestAssistStructureLocked(requestId, flags);
     }
@@ -1443,11 +1394,6 @@
             mSessionFlags = new SessionFlags();
             mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
             mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked();
-            if (mContext.checkCallingPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS)
-                    == PackageManager.PERMISSION_GRANTED) {
-                mSessionFlags.mClientSuggestionsEnabled =
-                        (mFlags & FLAG_ENABLED_CLIENT_SUGGESTIONS) != 0;
-            }
             setClientLocked(client);
         }
 
@@ -1599,15 +1545,14 @@
                 if (requestLog != null) {
                     requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
                 }
-                processNullResponseOrFallbackLocked(requestId, requestFlags);
+                processNullResponseLocked(requestId, requestFlags);
                 return;
             }
 
             // TODO: Check if this is required. We can still present datasets to the user even if
             //  traditional field classification is disabled.
             fieldClassificationIds = response.getFieldClassificationIds();
-            if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null
-                    && !mService.isFieldClassificationEnabledLocked()) {
+            if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
                 Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
                 processNullResponseLocked(requestId, requestFlags);
                 return;
@@ -1741,9 +1686,7 @@
                         || (ArrayUtils.isEmpty(saveInfo.getOptionalIds())
                             && ArrayUtils.isEmpty(saveInfo.getRequiredIds())
                             && ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) == 0)))
-                    && (ArrayUtils.isEmpty(response.getFieldClassificationIds())
-                        || (!mSessionFlags.mClientSuggestionsEnabled
-                        && !mService.isFieldClassificationEnabledLocked())));
+                    && (ArrayUtils.isEmpty(response.getFieldClassificationIds())));
         }
     }
 
@@ -2190,40 +2133,6 @@
         fieldFilters.add(dataset.getFilter(index));
     }
 
-    @GuardedBy("mLock")
-    private void processNullResponseOrFallbackLocked(int requestId, int flags) {
-        if (!mSessionFlags.mClientSuggestionsEnabled) {
-            processNullResponseLocked(requestId, flags);
-            return;
-        }
-
-        // fallback to the default platform password manager
-        mSessionFlags.mClientSuggestionsEnabled = false;
-        mLastFillDialogTriggerIds = null;
-        // Log the existing FillResponse event.
-        mFillResponseEventLogger.logAndEndEvent();
-
-        final InlineSuggestionsRequest inlineRequest =
-                (mLastInlineSuggestionsRequest != null
-                        && mLastInlineSuggestionsRequest.first == requestId)
-                        ? mLastInlineSuggestionsRequest.second : null;
-
-        // Start a new FillRequest logger for client suggestion fallback.
-        mFillRequestEventLogger.startLogForNewRequest();
-        mRequestCount++;
-        mFillRequestEventLogger.maybeSetAppPackageUid(uid);
-        mFillRequestEventLogger.maybeSetFlags(
-            flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
-        mFillRequestEventLogger.maybeSetRequestTriggerReason(
-            TRIGGER_REASON_NORMAL_TRIGGER);
-        mFillRequestEventLogger.maybeSetIsClientSuggestionFallback(true);
-
-        mAssistReceiver.newAutofillRequestLocked(inlineRequest);
-        requestAssistStructureLocked(requestId,
-                flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
-        return;
-    }
-
     // FillServiceCallbacks
     @Override
     @SuppressWarnings("GuardedBy")
@@ -2437,7 +2346,7 @@
                         + id + " destroyed");
                 return;
             }
-            fillInIntent = createAuthFillInIntentLocked(requestId, extras);
+            fillInIntent = createAuthFillInIntentLocked(requestId, extras, /* authExtras= */ null);
             if (fillInIntent == null) {
                 forceRemoveFromServiceLocked();
                 return;
@@ -4520,22 +4429,13 @@
             filterText = value.getTextValue().toString();
         }
 
-        final CharSequence targetLabel;
-        final Drawable targetIcon;
-        synchronized (mLock) {
-            if (mSessionFlags.mClientSuggestionsEnabled) {
-                final ApplicationInfo appInfo = ClientSuggestionsSession.getAppInfo(mComponentName,
-                        mService.getUserId());
-                targetLabel = ClientSuggestionsSession.getAppLabelLocked(
-                        mService.getMaster().getContext(), appInfo);
-                targetIcon = ClientSuggestionsSession.getAppIconLocked(
-                        mService.getMaster().getContext(), appInfo);
-            } else {
-                targetLabel = mService.getServiceLabelLocked();
-                targetIcon = mService.getServiceIconLocked();
-            }
+        final CharSequence serviceLabel;
+        final Drawable serviceIcon;
+        synchronized (this.mService.mLock) {
+            serviceLabel = mService.getServiceLabelLocked();
+            serviceIcon = mService.getServiceIconLocked();
         }
-        if (targetLabel == null || targetIcon == null) {
+        if (serviceLabel == null || serviceIcon == null) {
             wtf(null, "onFillReady(): no service label or icon");
             return;
         }
@@ -4596,7 +4496,7 @@
 
         getUiForShowing().showFillUi(filledId, response, filterText,
                 mService.getServicePackageName(), mComponentName,
-                targetLabel, targetIcon, this, mContext, id, mCompatMode,
+                serviceLabel, serviceIcon, this, mContext, id, mCompatMode,
                 mService.getMaster().getMaxInputLengthForAutofill());
 
         synchronized (mLock) {
@@ -4799,17 +4699,6 @@
             return false;
         }
 
-        final InlineSuggestionsRequest request = inlineSuggestionsRequest.get();
-        if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported()
-                || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) {
-            if (sDebug) {
-                Slog.d(TAG, "Inline suggestions not supported for "
-                        + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service")
-                        + ". Falling back to dropdown.");
-            }
-            return false;
-        }
-
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
         if (remoteRenderService == null) {
@@ -4824,7 +4713,7 @@
         }
 
         final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
-                new InlineFillUi.InlineFillUiInfo(request, focusedId,
+                new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
                         filterText, remoteRenderService, userId, id);
         InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
                 new InlineFillUi.InlineSuggestionUiCallback() {
@@ -5558,7 +5447,8 @@
             mPresentationStatsEventLogger.maybeSetAuthenticationType(
                 AUTHENTICATION_TYPE_DATASET_AUTHENTICATION);
             setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
-            final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState);
+            final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState,
+                    dataset.getAuthenticationExtras());
             if (fillInIntent == null) {
                 forceRemoveFromServiceLocked();
                 return;
@@ -5574,7 +5464,8 @@
     // TODO: this should never be null, but we got at least one occurrence, probably due to a race.
     @GuardedBy("mLock")
     @Nullable
-    private Intent createAuthFillInIntentLocked(int requestId, Bundle extras) {
+    private Intent createAuthFillInIntentLocked(int requestId, Bundle extras,
+            @Nullable Bundle authExtras) {
         final Intent fillInIntent = new Intent();
 
         final FillContext context = getFillContextByRequestIdLocked(requestId);
@@ -5591,6 +5482,9 @@
         }
         fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
         fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE, extras);
+        if (authExtras != null) {
+            fillInIntent.putExtra(AutofillManager.EXTRA_AUTH_STATE, authExtras);
+        }
         return fillInIntent;
     }
 
@@ -5636,26 +5530,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void onClientFillRequestLocked(int requestId,
-            InlineSuggestionsRequest inlineSuggestionsRequest) {
-        if (mClientSuggestionsSession == null) {
-            mClientSuggestionsSession = new ClientSuggestionsSession(id, mClient, mHandler,
-                    mComponentName, this);
-        }
-
-        if (mContexts == null) {
-            mContexts = new ArrayList<>(1);
-        }
-        mContexts.add(new FillContext(requestId, new AssistStructure(), mCurrentViewId));
-
-        if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) {
-            inlineSuggestionsRequest = null;
-        }
-
-        mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags);
-    }
-
     /**
      * The result of checking whether to show the save dialog, when session can be saved.
      *
@@ -6137,9 +6011,17 @@
                         continue;
                     }
                     final AutofillId viewId = dataset.getFieldIds().get(i);
+                    final ViewState viewState = mViewStates.get(viewId);
+                    if (mService.getMaster().getIsFillFieldsFromCurrentSessionOnly()
+                            && viewState != null && viewState.id.getSessionId() != id) {
+                        if (sVerbose) {
+                            Slog.v(TAG, "Skipping filling view: " +
+                                    viewId + " as it isn't part of the current session: " + id);
+                        }
+                        continue;
+                    }
                     ids.add(viewId);
                     values.add(dataset.getFieldValues().get(i));
-                    final ViewState viewState = mViewStates.get(viewId);
                     if (viewState != null
                             && (viewState.getState() & ViewState.STATE_WAITING_DATASET_AUTH) != 0) {
                         if (sVerbose) {
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 9dd0dca..852e36d 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -218,6 +218,9 @@
 
     void setActivityLaunchDefaultAllowed(boolean activityLaunchDefaultAllowed) {
         synchronized (mGenericWindowPolicyControllerLock) {
+            if (mActivityLaunchAllowedByDefault != activityLaunchDefaultAllowed) {
+                mActivityPolicyExemptions.clear();
+            }
             mActivityLaunchAllowedByDefault = activityLaunchDefaultAllowed;
         }
     }
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index cfe56e9..5cb100a1 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -38,6 +38,7 @@
 import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.flags.Flags;
 import android.companion.virtual.sensor.VirtualSensor;
+import android.companion.virtualnative.IVirtualDeviceManagerNative;
 import android.content.AttributionSource;
 import android.content.Context;
 import android.content.Intent;
@@ -88,8 +89,11 @@
 
     private static final String TAG = "VirtualDeviceManagerService";
 
+    private static final String VIRTUAL_DEVICE_NATIVE_SERVICE = "virtualdevice_native";
+
     private final Object mVirtualDeviceManagerLock = new Object();
     private final VirtualDeviceManagerImpl mImpl;
+    private final VirtualDeviceManagerNativeImpl mNativeImpl;
     private final VirtualDeviceManagerInternal mLocalService;
     private VirtualDeviceLog mVirtualDeviceLog = new VirtualDeviceLog(getContext());
     private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -125,6 +129,7 @@
     public VirtualDeviceManagerService(Context context) {
         super(context);
         mImpl = new VirtualDeviceManagerImpl();
+        mNativeImpl = Flags.enableNativeVdm() ? new VirtualDeviceManagerNativeImpl() : null;
         mLocalService = new LocalService();
     }
 
@@ -155,6 +160,9 @@
     @Override
     public void onStart() {
         publishBinderService(Context.VIRTUAL_DEVICE_SERVICE, mImpl);
+        if (Flags.enableNativeVdm()) {
+            publishBinderService(VIRTUAL_DEVICE_NATIVE_SERVICE, mNativeImpl);
+        }
         publishLocalService(VirtualDeviceManagerInternal.class, mLocalService);
         ActivityTaskManagerInternal activityTaskManagerInternal = getLocalService(
                 ActivityTaskManagerInternal.class);
@@ -590,6 +598,19 @@
         }
     }
 
+    final class VirtualDeviceManagerNativeImpl extends IVirtualDeviceManagerNative.Stub {
+        @Override // Binder call
+        public int[] getDeviceIdsForUid(int uid) {
+            return mLocalService
+                    .getDeviceIdsForUid(uid).stream().mapToInt(Integer::intValue).toArray();
+        }
+
+        @Override // Binder call
+        public int getDevicePolicy(int deviceId, int policyType) {
+            return mImpl.getDevicePolicy(deviceId, policyType);
+        }
+    }
+
     private final class LocalService extends VirtualDeviceManagerInternal {
         @GuardedBy("mVirtualDeviceManagerLock")
         private final ArrayList<VirtualDisplayListener>
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 6521fab..e5225f6 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -183,6 +183,7 @@
         "cbor-java",
         "display_flags_lib",
         "icu4j_calendar_astronomer",
+        "android.security.aaid_aidl-java",
         "netd-client",
         "overlayable_policy_aidl-java",
         "SurfaceFlingerProperties",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index cd87908..8df5456 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1428,6 +1428,12 @@
             @UserIdInt int userId);
 
     /**
+     * Sends the PACKAGE_RESTARTED broadcast on the package manager handler thread.
+     */
+    public abstract void sendPackageRestartedBroadcast(@NonNull String packageName,
+            int uid, @Intent.Flags int flags);
+
+    /**
      * Return a list of all historical install sessions for the given user.
      */
     public abstract ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions(
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 556eba6..e9d4d76 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import static android.os.Flags.stateOfHealthPublic;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import static com.android.server.health.Utils.copyV1Battery;
 
@@ -27,7 +28,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.hardware.health.HealthInfo;
 import android.hardware.health.V2_1.BatteryCapacityLevel;
@@ -1333,10 +1333,14 @@
         @Override
         public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
             switch (id) {
+                case BatteryManager.BATTERY_PROPERTY_STATE_OF_HEALTH:
+                    if (stateOfHealthPublic()) {
+                        break;
+                    }
+
                 case BatteryManager.BATTERY_PROPERTY_MANUFACTURING_DATE:
                 case BatteryManager.BATTERY_PROPERTY_FIRST_USAGE_DATE:
                 case BatteryManager.BATTERY_PROPERTY_CHARGING_POLICY:
-                case BatteryManager.BATTERY_PROPERTY_STATE_OF_HEALTH:
                     mContext.enforceCallingPermission(
                             android.Manifest.permission.BATTERY_STATS, null);
                     break;
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index d47a399..db89cac 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -87,7 +87,7 @@
 # replaces 27510 with a row per notification
 27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1)
 # a notification emited noise, vibration, or light
-27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1)
+27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1),(politeness|1)
 # a notification was added to a autogroup
 27533 notification_autogrouped (key|3)
 # notification was removed from an autogroup
diff --git a/services/core/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java
index 20de40e..3d610d3 100644
--- a/services/core/java/com/android/server/ExplicitHealthCheckController.java
+++ b/services/core/java/com/android/server/ExplicitHealthCheckController.java
@@ -343,7 +343,7 @@
             };
 
             mContext.bindServiceAsUser(intent, mConnection,
-                    Context.BIND_AUTO_CREATE, UserHandle.of(UserHandle.USER_SYSTEM));
+                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
             Slog.i(TAG, "Explicit health check service is bound");
         }
     }
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 55130e4..987507f 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -16,9 +16,6 @@
 # ServiceWatcher
 per-file ServiceWatcher.java = sooniln@google.com
 
-# Health
-per-file BatteryService.java = file:platform/hardware/interfaces:/health/aidl/OWNERS
-
 per-file *Accessibility* = file:/services/accessibility/OWNERS
 per-file *Alarm* = file:/apex/jobscheduler/OWNERS
 per-file *AppOp* = file:/core/java/android/permission/OWNERS
@@ -39,7 +36,7 @@
 per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS
 per-file PackageWatchdog.java, RescueParty.java = file:/services/core/java/com/android/server/rollback/OWNERS
 per-file PinnerService.java = file:/apct-tests/perftests/OWNERS
-per-file RescueParty.java = fdunlap@google.com, shuc@google.com, ancr@google.com, harshitmahajan@google.com
+per-file RescueParty.java = shuc@google.com, ancr@google.com, harshitmahajan@google.com
 per-file SystemClockTime.java = file:/services/core/java/com/android/server/timedetector/OWNERS
 per-file SystemTimeZone.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS
 per-file TelephonyRegistry.java = file:/telephony/OWNERS
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 9bab261..57ed5a2 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -41,6 +41,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
@@ -153,6 +154,9 @@
     @GuardedBy("this")
     private ArraySet<Integer> mPinKeys;
 
+    private static final String DEVICE_CONFIG_KEY_ANON_SIZE = "pin_shared_anon_size";
+    private static final long DEFAULT_ANON_SIZE =
+            SystemProperties.getLong("pinner.pin_shared_anon_size", 0);
     private static final long MAX_ANON_SIZE = 2L * (1L << 30); // 2GB
     private long mPinAnonSize;
     private long mPinAnonAddress;
@@ -180,6 +184,17 @@
         }
     };
 
+    private DeviceConfig.OnPropertiesChangedListener mDeviceConfigListener =
+            new DeviceConfig.OnPropertiesChangedListener() {
+                @Override
+                public void onPropertiesChanged(DeviceConfig.Properties properties) {
+                    if (DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT.equals(properties.getNamespace())
+                            && properties.getKeyset().contains(DEVICE_CONFIG_KEY_ANON_SIZE)) {
+                        refreshPinAnonConfig();
+                    }
+                }
+            };
+
     public PinnerService(Context context) {
         super(context);
 
@@ -206,6 +221,11 @@
 
         registerUidListener();
         registerUserSetupCompleteListener();
+
+        DeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+                new HandlerExecutor(mPinnerHandler),
+                mDeviceConfigListener);
     }
 
     @Override
@@ -344,6 +364,8 @@
                 }
             }
         }
+
+        refreshPinAnonConfig();
     }
 
     /**
@@ -359,8 +381,10 @@
                     @Override
                     public void onChange(boolean selfChange, Uri uri) {
                         if (userSetupCompleteUri.equals(uri)) {
-                            sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(),
-                                    true /* force */);
+                            if (mConfiguredToPinHome) {
+                                sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(),
+                                        true /* force */);
+                            }
                         }
                     }
                 }, UserHandle.USER_ALL);
@@ -558,11 +582,6 @@
             pinKeys.add(KEY_ASSISTANT);
         }
 
-        mPinAnonSize = DeviceConfig.getLong(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
-                "pin_anon_size",
-                SystemProperties.getLong("pinner.pin_anon_size", 0));
-        mPinAnonSize = Math.max(0, Math.min(mPinAnonSize, MAX_ANON_SIZE));
-
         return pinKeys;
     }
 
@@ -602,7 +621,6 @@
             int key = currentPinKeys.valueAt(i);
             pinApp(key, userHandle, true /* force */);
         }
-        pinAnonRegion();
     }
 
     /**
@@ -687,10 +705,28 @@
     }
 
     /**
+     * Handle any changes in the anon region pinner config.
+     */
+    private void refreshPinAnonConfig() {
+        long newPinAnonSize =
+                DeviceConfig.getLong(
+                        DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+                        DEVICE_CONFIG_KEY_ANON_SIZE,
+                        DEFAULT_ANON_SIZE);
+        newPinAnonSize = Math.max(0, Math.min(newPinAnonSize, MAX_ANON_SIZE));
+        if (newPinAnonSize != mPinAnonSize) {
+            mPinAnonSize = newPinAnonSize;
+            pinAnonRegion();
+        }
+    }
+
+    /**
      * Pin an empty anonymous region. This should only be used for ablation experiments.
      */
     private void pinAnonRegion() {
         if (mPinAnonSize == 0) {
+            Slog.d(TAG, "pinAnonRegion: releasing pinned region");
+            unpinAnonRegion();
             return;
         }
         long alignedPinSize = mPinAnonSize;
@@ -698,15 +734,21 @@
             alignedPinSize -= alignedPinSize % PAGE_SIZE;
             Slog.e(TAG, "pinAnonRegion: aligning size to " + alignedPinSize);
         }
-        if (mPinAnonAddress != 0
-                && mCurrentlyPinnedAnonSize != alignedPinSize) {
+        if (mPinAnonAddress != 0) {
+            if (mCurrentlyPinnedAnonSize == alignedPinSize) {
+                Slog.d(TAG, "pinAnonRegion: already pinned region of size " + alignedPinSize);
+                return;
+            }
+            Slog.d(TAG, "pinAnonRegion: resetting pinned region for new size " + alignedPinSize);
             unpinAnonRegion();
         }
         long address = 0;
         try {
+            // Map as SHARED to avoid changing rss.anon for system_server (per /proc/*/status).
+            // The mapping is visible in other rss metrics, and as private dirty in smaps/meminfo.
             address = Os.mmap(0, alignedPinSize,
                     OsConstants.PROT_READ | OsConstants.PROT_WRITE,
-                    OsConstants.MAP_PRIVATE | OsConstants.MAP_ANONYMOUS,
+                    OsConstants.MAP_SHARED | OsConstants.MAP_ANONYMOUS,
                     new FileDescriptor(), /*offset=*/0);
 
             Unsafe tempUnsafe = null;
@@ -727,7 +769,7 @@
             mCurrentlyPinnedAnonSize = alignedPinSize;
             mPinAnonAddress = address;
             address = -1;
-            Slog.e(TAG, "pinAnonRegion success, size=" + mCurrentlyPinnedAnonSize);
+            Slog.w(TAG, "pinAnonRegion success, size=" + mCurrentlyPinnedAnonSize);
         } catch (Exception ex) {
             Slog.e(TAG, "Could not pin anon region of size " + alignedPinSize, ex);
             return;
@@ -742,6 +784,8 @@
         if (mPinAnonAddress != 0) {
             safeMunmap(mPinAnonAddress, mCurrentlyPinnedAnonSize);
         }
+        mPinAnonAddress = 0;
+        mCurrentlyPinnedAnonSize = 0;
     }
 
     /**
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index c094c12..dd54334 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -522,7 +522,8 @@
         Exception res = null;
         final ContentResolver resolver = context.getContentResolver();
         try {
-            Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
+            Settings.Global.resetToDefaultsAsUser(resolver, null, mode,
+                UserHandle.SYSTEM.getIdentifier());
         } catch (Exception e) {
             res = new RuntimeException("Failed to reset global settings", e);
         }
@@ -779,12 +780,13 @@
     }
 
     private static int[] getAllUserIds() {
-        int[] userIds = { UserHandle.USER_SYSTEM };
+        int systemUserId = UserHandle.SYSTEM.getIdentifier();
+        int[] userIds = { systemUserId };
         try {
             for (File file : FileUtils.listFilesOrEmpty(Environment.getDataSystemDeDirectory())) {
                 try {
                     final int userId = Integer.parseInt(file.getName());
-                    if (userId != UserHandle.USER_SYSTEM) {
+                    if (userId != systemUserId) {
                         userIds = ArrayUtils.appendInt(userIds, userId);
                     }
                 } catch (NumberFormatException ignored) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 8cc2665..962f38f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -214,6 +214,9 @@
     // external storage service.
     public static final int FAILED_MOUNT_RESET_TIMEOUT_SECONDS = 10;
 
+     /** Extended timeout for the system server watchdog. */
+    private static final int SLOW_OPERATION_WATCHDOG_TIMEOUT_MS = 60 * 1000;
+
     @GuardedBy("mLock")
     private final Set<Integer> mFuseMountedUser = new ArraySet<>();
 
@@ -1230,6 +1233,8 @@
     private void onUserStopped(int userId) {
         Slog.d(TAG, "onUserStopped " + userId);
 
+        Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#onUserStopped might be slow");
         try {
             mVold.onUserStopped(userId);
             mStoraged.onUserStopped(userId);
@@ -1312,6 +1317,8 @@
                 unlockedUsers.add(userId);
             }
         }
+        Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#onUserStopped might be slow");
         for (Integer userId : unlockedUsers) {
             try {
                 mVold.onUserStopped(userId);
@@ -3600,6 +3607,8 @@
 
         @Override
         public ParcelFileDescriptor open() throws AppFuseMountException {
+            Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#open might be slow");
             try {
                 final FileDescriptor fd = mVold.mountAppFuse(uid, mountId);
                 mMounted = true;
@@ -3612,6 +3621,8 @@
         @Override
         public ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
                 throws AppFuseMountException {
+            Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#openFile might be slow");
             try {
                 return new ParcelFileDescriptor(
                         mVold.openAppFuseFile(uid, mountId, fileId, flags));
@@ -3622,6 +3633,8 @@
 
         @Override
         public void close() throws Exception {
+            Watchdog.getInstance().setOneOffTimeoutForMonitors(
+                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#close might be slow");
             if (mMounted) {
                 mVold.unmountAppFuse(uid, mountId);
                 mMounted = false;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 6e984bb..55aa716 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -330,7 +330,7 @@
         String describeBlockedStateLocked() {
             final String prefix;
             if (mCurrentMonitor == null) {
-                prefix = "Blocked in handler on ";
+                prefix = "Blocked in handler";
             } else {
                 prefix =  "Blocked in monitor " + mCurrentMonitor.getClass().getName();
             }
@@ -644,6 +644,16 @@
     }
 
     /**
+     * Sets a one-off timeout for the next run of the watchdog for the monitor thread.
+     *
+     * <p>Simiar to {@link setOneOffTimeoutForCurrentThread} but used for monitors added through
+     * {@link #addMonitor}
+     */
+    public void setOneOffTimeoutForMonitors(int oneOffTimeoutMillis, String reason) {
+        mMonitorChecker.setOneOffTimeoutLocked(oneOffTimeoutMillis, reason);
+    }
+
+    /**
      * Pauses Watchdog action for the currently running thread. Useful before executing long running
      * operations that could falsely trigger the watchdog. Each call to this will require a matching
      * call to {@link #resumeWatchingCurrentThread}.
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 330742a..5fb889a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5023,7 +5023,7 @@
             p.setDataPosition(0);
             Bundle simulateBundle = p.readBundle();
             p.recycle();
-            Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+            Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
             if (intent != null && intent.getClass() != Intent.class) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d3ce47c..a97f005 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -377,6 +377,7 @@
 import android.util.IndentingPrintWriter;
 import android.util.IntArray;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
@@ -562,7 +563,7 @@
     static final int PROC_START_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     // How long we wait for a launched process to complete its app startup before we ANR.
-    static final int BIND_APPLICATION_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
+    static final int BIND_APPLICATION_TIMEOUT = 15 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     // How long we wait to kill an application zygote, after the last process using
     // it has gone away.
@@ -1630,7 +1631,8 @@
     static final int UPDATE_CACHED_APP_HIGH_WATERMARK = 79;
     static final int ADD_UID_TO_OBSERVER_MSG = 80;
     static final int REMOVE_UID_FROM_OBSERVER_MSG = 81;
-    static final int BIND_APPLICATION_TIMEOUT_MSG = 82;
+    static final int BIND_APPLICATION_TIMEOUT_SOFT_MSG = 82;
+    static final int BIND_APPLICATION_TIMEOUT_HARD_MSG = 83;
 
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
 
@@ -1983,15 +1985,11 @@
                 case UPDATE_CACHED_APP_HIGH_WATERMARK: {
                     mAppProfiler.mCachedAppsWatermarkData.updateCachedAppsSnapshot((long) msg.obj);
                 } break;
-                case BIND_APPLICATION_TIMEOUT_MSG: {
-                    ProcessRecord app = (ProcessRecord) msg.obj;
-
-                    final String anrMessage;
-                    synchronized (app) {
-                        anrMessage = "Process " + app + " failed to complete startup";
-                    }
-
-                    mAnrHelper.appNotResponding(app, TimeoutRecord.forAppStart(anrMessage));
+                case BIND_APPLICATION_TIMEOUT_SOFT_MSG: {
+                    handleBindApplicationTimeoutSoft((ProcessRecord) msg.obj, msg.arg1);
+                } break;
+                case BIND_APPLICATION_TIMEOUT_HARD_MSG: {
+                    handleBindApplicationTimeoutHard((ProcessRecord) msg.obj);
                 } break;
             }
         }
@@ -4160,26 +4158,34 @@
 
     @GuardedBy("this")
     private void finishForceStopPackageLocked(final String packageName, int uid) {
-        Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
-                Uri.fromParts("package", packageName, null));
+        int flags = 0;
         if (!mProcessesReady) {
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                    | Intent.FLAG_RECEIVER_FOREGROUND);
+            flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                    | Intent.FLAG_RECEIVER_FOREGROUND;
         }
-        final int userId = UserHandle.getUserId(uid);
-        final int[] broadcastAllowList =
-                getPackageManagerInternal().getVisibilityAllowList(packageName, userId);
-        intent.putExtra(Intent.EXTRA_UID, uid);
-        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-        broadcastIntentLocked(null /* callerApp */, null /* callerPackage */,
-                null /* callerFeatureId */, intent, null /* resolvedType */,
-                null /* resultToApp */, null /* resultTo */,
-                0 /* resultCode */, null /* resultData */, null /* resultExtras */,
-                null /* requiredPermissions */, null /* excludedPermissions */,
-                null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */,
-                false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
-                Binder.getCallingPid(), userId, BackgroundStartPrivileges.NONE,
-                broadcastAllowList, null /* filterExtrasForReceiver */);
+        if (android.content.pm.Flags.stayStopped()) {
+            // Sent async using the PM handler, to maintain ordering with PACKAGE_UNSTOPPED
+            mPackageManagerInt.sendPackageRestartedBroadcast(packageName,
+                    uid, flags);
+        } else {
+            Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
+                    Uri.fromParts("package", packageName, null));
+            intent.addFlags(flags);
+            final int userId = UserHandle.getUserId(uid);
+            final int[] broadcastAllowList =
+                    getPackageManagerInternal().getVisibilityAllowList(packageName, userId);
+            intent.putExtra(Intent.EXTRA_UID, uid);
+            intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+            broadcastIntentLocked(null /* callerApp */, null /* callerPackage */,
+                    null /* callerFeatureId */, intent, null /* resolvedType */,
+                    null /* resultToApp */, null /* resultTo */,
+                    0 /* resultCode */, null /* resultData */, null /* resultExtras */,
+                    null /* requiredPermissions */, null /* excludedPermissions */,
+                    null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */,
+                    false /* sticky */, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                    Binder.getCallingPid(), userId, BackgroundStartPrivileges.NONE,
+                    broadcastAllowList, null /* filterExtrasForReceiver */);
+        }
     }
 
     private void cleanupDisabledPackageComponentsLocked(
@@ -4749,6 +4755,7 @@
                 mPlatformCompat.resetReporting(app.info);
             }
             final ProviderInfoList providerList = ProviderInfoList.fromList(providers);
+            app.mProfile.mLastCpuDelayTime.set(app.getCpuDelayTime());
             if (app.getIsolatedEntryPoint() != null) {
                 // This is an isolated process which should just call an entry point instead of
                 // being bound to an application.
@@ -4786,9 +4793,10 @@
                         app.getStartElapsedTime(), app.getStartUptime());
             }
 
-            Message msg = mHandler.obtainMessage(BIND_APPLICATION_TIMEOUT_MSG);
+            Message msg = mHandler.obtainMessage(BIND_APPLICATION_TIMEOUT_SOFT_MSG);
             msg.obj = app;
-            mHandler.sendMessageDelayed(msg, BIND_APPLICATION_TIMEOUT);
+            msg.arg1 = BIND_APPLICATION_TIMEOUT;
+            mHandler.sendMessageDelayed(msg, msg.arg1 /* BIND_APPLICATION_TIMEOUT */);
             mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
 
             if (profilerInfo != null) {
@@ -4865,7 +4873,8 @@
         }
 
         if (app != null && app.getStartUid() == uid && app.getStartSeq() == startSeq) {
-            mHandler.removeMessages(BIND_APPLICATION_TIMEOUT_MSG, app);
+            mHandler.removeMessages(BIND_APPLICATION_TIMEOUT_SOFT_MSG, app);
+            mHandler.removeMessages(BIND_APPLICATION_TIMEOUT_HARD_MSG, app);
         } else {
             Slog.wtf(TAG, "Mismatched or missing ProcessRecord: " + app + ". Pid: " + pid
                     + ". Uid: " + uid);
@@ -5002,6 +5011,35 @@
         }
     }
 
+    private void handleBindApplicationTimeoutSoft(ProcessRecord app, int softTimeoutMillis) {
+        // Similar logic as the broadcast delivery timeout:
+        // instead of immediately triggering an ANR, extend the timeout by
+        // the amount of time the process was runnable-but-waiting; we're
+        // only willing to do this once before triggering an hard ANR.
+        final long cpuDelayTime = app.getCpuDelayTime() - app.mProfile.mLastCpuDelayTime.get();
+        final long hardTimeoutMillis = MathUtils.constrain(cpuDelayTime, 0, softTimeoutMillis);
+
+        if (hardTimeoutMillis == 0) {
+            handleBindApplicationTimeoutHard(app);
+            return;
+        }
+
+        Slog.i(TAG, "Extending process start timeout by " + hardTimeoutMillis + "ms for " + app);
+        Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplicationTimeSoft "
+                + app.processName + "(" + app.getPid() + ")");
+        final Message msg = mHandler.obtainMessage(BIND_APPLICATION_TIMEOUT_HARD_MSG, app);
+        mHandler.sendMessageDelayed(msg, hardTimeoutMillis);
+    }
+
+    private void handleBindApplicationTimeoutHard(ProcessRecord app) {
+        final String anrMessage;
+        synchronized (app) {
+            anrMessage = "Process " + app + " failed to complete startup";
+        }
+
+        mAnrHelper.appNotResponding(app, TimeoutRecord.forAppStart(anrMessage));
+    }
+
     /**
      * @return The last part of the string of an intent's action.
      */
diff --git a/services/core/java/com/android/server/am/AnrTimer.java b/services/core/java/com/android/server/am/AnrTimer.java
index 378a386..9ba49ce 100644
--- a/services/core/java/com/android/server/am/AnrTimer.java
+++ b/services/core/java/com/android/server/am/AnrTimer.java
@@ -108,6 +108,14 @@
     private static final boolean ENABLE_TRACING = false;
 
     /**
+     * Return true if the feature is enabled.  By default, the value is take from the Flags class
+     * but it can be changed for local testing.
+     */
+    private static boolean anrTimerServiceEnabled() {
+        return Flags.anrTimerServiceEnabled();
+    }
+
+    /**
      * The status of an ANR timer.  TIMER_INVALID status is returned when an error is detected.
      */
     private static final int TIMER_INVALID = 0;
@@ -327,18 +335,33 @@
      */
     @VisibleForTesting
     static class Injector {
-        /**
-         * Return a handler for the given Callback.
-         */
-        Handler getHandler(@NonNull Handler.Callback callback) {
-            return null;
-        };
+        private final Handler mReferenceHandler;
+
+        Injector(@NonNull Handler handler) {
+            mReferenceHandler = handler;
+        }
 
         /**
-         * Return a CpuTracker.
+         * Return a handler for the given Callback, based on the reference handler. The handler
+         * might be mocked, in which case it does not have a valid Looper.  In this case, use the
+         * main Looper.
          */
+        @NonNull
+        Handler getHandler(@NonNull Handler.Callback callback) {
+            Looper looper = mReferenceHandler.getLooper();
+            if (looper == null) looper = Looper.getMainLooper();
+            return new Handler(looper, callback);
+        };
+
+        /** Return a CpuTracker. */
+        @NonNull
         CpuTracker getTracker() {
-            return null;
+            return new CpuTracker();
+        }
+
+        /** Return true if the feature is enabled. */
+        boolean getFeatureEnabled() {
+            return anrTimerServiceEnabled();
         }
     }
 
@@ -375,12 +398,6 @@
         /** The interface to fetch process statistics that might extend an ANR timeout. */
         private final CpuTracker mCpu;
 
-        /** Create a HandlerTimerService based on the input handler. */
-        HandlerTimerService(@NonNull Handler handler) {
-            mHandler = new Handler(handler.getLooper(), this::expires);
-            mCpu = new CpuTracker();
-        }
-
         /** Create a HandlerTimerService that directly uses the supplied handler and tracker. */
         @VisibleForTesting
         HandlerTimerService(@NonNull Injector injector) {
@@ -491,38 +508,56 @@
     private final boolean mLenientCancel = true;
 
     /**
+     * The top-level switch for the feature enabled or disabled.
+     */
+    private final FeatureSwitch mFeature;
+
+    /**
      * The common constructor.  A null injector results in a normal, production timer.
      */
     @VisibleForTesting
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend,
-            @Nullable Injector injector) {
+            @NonNull Injector injector) {
         mHandler = handler;
         mWhat = what;
         mLabel = label;
         mExtend = extend;
-        if (injector == null) {
-            mTimerService = new HandlerTimerService(handler);
+        boolean enabled = injector.getFeatureEnabled();
+        if (!enabled) {
+            mFeature = new FeatureDisabled();
+            mTimerService = null;
         } else {
+            mFeature = new FeatureEnabled();
             mTimerService = new HandlerTimerService(injector);
+
+            synchronized (sAnrTimerList) {
+                sAnrTimerList.add(new WeakReference(this));
+            }
         }
-        synchronized (sAnrTimerList) {
-            sAnrTimerList.add(new WeakReference(this));
-        }
-        Log.i(TAG, formatSimple("created %s label: \"%s\"", mTimerService.toString(), label));
+        Log.i(TAG, formatSimple("created %s label: \"%s\"", mTimerService, label));
     }
 
     /**
      * Create one timer instance for production.  The client can ask for extensible timeouts.
      */
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) {
-        this(handler, what, label, extend, null);
+        this(handler, what, label, extend, new Injector(handler));
     }
 
     /**
      * Create one timer instance for production.  There are no extensible timeouts.
      */
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label) {
-        this(handler, what, label, false, null);
+        this(handler, what, label, false);
+    }
+
+    /**
+     * Return true if the service is enabled on this instance.  Clients should use this method to
+     * decide if the feature is enabled, and not read the flags directly.  This method should be
+     * deleted if and when the feature is enabled permanently.
+     */
+    boolean serviceEnabled() {
+        return mFeature.enabled();
     }
 
     /**
@@ -613,93 +648,186 @@
         Log.i(TAG, msg + " " + timer + " " + Objects.toString(timer.arg));
     }
 
-   /**
-     * Start a timer.
+    /**
+     * The FeatureSwitch class provides a quick switch between feature-enabled behavior and
+     * feature-disabled behavior.
      */
-    boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
-        final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, this);
-        synchronized (mLock) {
-            Timer old = mTimerMap.get(arg);
-            if (old != null) {
-                // There is an existing timer.  This is a protocol error in the client.  Record
-                // the error and then clean up by canceling running timers and discarding expired
-                // timers.
-                restartedLocked(old.status, arg);
-                if (old.status == TIMER_EXPIRED) {
-                    discard(arg);
+    private abstract class FeatureSwitch {
+        abstract boolean start(@NonNull V arg, int pid, int uid, long timeoutMs);
+        abstract boolean cancel(@NonNull V arg);
+        abstract boolean accept(@NonNull V arg);
+        abstract boolean discard(@NonNull V arg);
+        abstract boolean enabled();
+    }
+
+    /**
+     * The FeatureDisabled class bypasses almost all AnrTimer logic.  It is used when the AnrTimer
+     * service is disabled via Flags.anrTimerServiceEnabled.
+     */
+    private class FeatureDisabled extends FeatureSwitch {
+        /** Start a timer by sending a message to the client's handler. */
+        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
+            final Message msg = mHandler.obtainMessage(mWhat, arg);
+            mHandler.sendMessageDelayed(msg, timeoutMs);
+            return true;
+        }
+
+        /** Cancel a timer by removing the message from the client's handler. */
+        boolean cancel(@NonNull V arg) {
+            mHandler.removeMessages(mWhat, arg);
+            return true;
+        }
+
+        /** accept() is a no-op when the feature is disabled. */
+        boolean accept(@NonNull V arg) {
+            return true;
+        }
+
+        /** discard() is a no-op when the feature is disabled. */
+        boolean discard(@NonNull V arg) {
+            return true;
+        }
+
+        /** The feature is not enabled. */
+        boolean enabled() {
+            return false;
+        }
+    }
+
+    /**
+     * The FeatureEnabled class enables the AnrTimer logic.  It is used when the AnrTimer service
+     * is enabled via Flags.anrTimerServiceEnabled.
+     */
+    private class FeatureEnabled extends FeatureSwitch {
+
+        /**
+         * Start a timer.
+         */
+        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
+            final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, AnrTimer.this);
+            synchronized (mLock) {
+                Timer old = mTimerMap.get(arg);
+                if (old != null) {
+                    // There is an existing timer.  This is a protocol error in the client.
+                    // Record the error and then clean up by canceling running timers and
+                    // discarding expired timers.
+                    restartedLocked(old.status, arg);
+                    if (old.status == TIMER_EXPIRED) {
+                        discard(arg);
+                    } else {
+                        cancel(arg);
+                    }
+                }
+                if (mTimerService.start(timer)) {
+                    timer.status = TIMER_RUNNING;
+                    mTimerMap.put(arg, timer);
+                    mTotalStarted++;
+                    mMaxStarted = Math.max(mMaxStarted, mTimerMap.size());
+                    if (DEBUG) report(timer, "start");
+                    return true;
                 } else {
-                    cancel(arg);
+                    Log.e(TAG, "AnrTimer.start failed");
+                    return false;
                 }
             }
-            if (mTimerService.start(timer)) {
-                timer.status = TIMER_RUNNING;
-                mTimerMap.put(arg, timer);
-                mTotalStarted++;
-                mMaxStarted = Math.max(mMaxStarted, mTimerMap.size());
-                if (DEBUG) report(timer, "start");
+        }
+
+        /**
+         * Cancel a timer.  Return false if the timer was not found.
+         */
+        boolean cancel(@NonNull V arg) {
+            synchronized (mLock) {
+                Timer timer = removeLocked(arg);
+                if (timer == null) {
+                    if (!mLenientCancel) notFoundLocked("cancel", arg);
+                    return false;
+                }
+                mTimerService.cancel(timer);
+                // There may be an expiration message in flight.  Cancel it.
+                mHandler.removeMessages(mWhat, arg);
+                if (DEBUG) report(timer, "cancel");
+                timer.release();
                 return true;
-            } else {
-                Log.e(TAG, "AnrTimer.start failed");
-                return false;
             }
         }
+
+        /**
+         * Accept a timer in the framework-level handler.  The timeout has been accepted and the
+         * timeout handler is executing.  Return false if the timer was not found.
+         */
+        boolean accept(@NonNull V arg) {
+            synchronized (mLock) {
+                Timer timer = removeLocked(arg);
+                if (timer == null) {
+                    notFoundLocked("accept", arg);
+                    return false;
+                }
+                mTimerService.accept(timer);
+                traceEnd(timer);
+                if (DEBUG) report(timer, "accept");
+                timer.release();
+                return true;
+            }
+        }
+
+        /**
+         * Discard a timer in the framework-level handler.  For whatever reason, the timer is no
+         * longer interesting.  No statistics are collected.  Return false if the time was not
+         * found.
+         */
+        boolean discard(@NonNull V arg) {
+            synchronized (mLock) {
+                Timer timer = removeLocked(arg);
+                if (timer == null) {
+                    notFoundLocked("discard", arg);
+                    return false;
+                }
+                mTimerService.discard(timer);
+                traceEnd(timer);
+                if (DEBUG) report(timer, "discard");
+                timer.release();
+                return true;
+            }
+        }
+
+        /** The feature is enabled. */
+        boolean enabled() {
+            return true;
+        }
     }
 
     /**
-     * Cancel a timer.  Return false if the timer was not found.
+     * Start a timer associated with arg.  If a timer already exists with the same arg, then that
+     * timer is canceled and a new timer is created.  This returns false if the timer cannot be
+     * created.
+     */
+    boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
+        return mFeature.start(arg, pid, uid, timeoutMs);
+    }
+
+    /**
+     * Cancel a running timer and remove it from any list.  This returns true if the timer was
+     * found and false otherwise.  It is not an error to cancel a non-existent timer.  It is also
+     * not an error to cancel an expired timer.
      */
     boolean cancel(@NonNull V arg) {
-        synchronized (mLock) {
-            Timer timer = removeLocked(arg);
-            if (timer == null) {
-                if (!mLenientCancel) notFoundLocked("cancel", arg);
-                return false;
-            }
-            mTimerService.cancel(timer);
-            // There may be an expiration message in flight.  Cancel it.
-            mHandler.removeMessages(mWhat, arg);
-            if (DEBUG) report(timer, "cancel");
-            timer.release();
-            return true;
-        }
+        return mFeature.cancel(arg);
     }
 
     /**
-     * Accept a timer in the framework-level handler.  The timeout has been accepted and the
-     * timeout handler is executing.  Return false if the timer was not found.
+     * Accept an expired timer.  This returns false if the timer was not found or if the timer was
+     * not expired.
      */
     boolean accept(@NonNull V arg) {
-        synchronized (mLock) {
-            Timer timer = removeLocked(arg);
-            if (timer == null) {
-                notFoundLocked("accept", arg);
-                return false;
-            }
-            mTimerService.accept(timer);
-            traceEnd(timer);
-            if (DEBUG) report(timer, "accept");
-            timer.release();
-            return true;
-        }
+        return mFeature.accept(arg);
     }
 
     /**
-     * Discard a timer in the framework-level handler.  For whatever reason, the timer is no
-     * longer interesting.  No statistics are collected.  Return false if the time was not found.
+     * Discard an expired timer.  This returns false if the timer was not found or if the timer was
+     * not expired.
      */
     boolean discard(@NonNull V arg) {
-        synchronized (mLock) {
-            Timer timer = removeLocked(arg);
-            if (timer == null) {
-                notFoundLocked("discard", arg);
-                return false;
-            }
-            mTimerService.discard(timer);
-            traceEnd(timer);
-            if (DEBUG) report(timer, "discard");
-            timer.release();
-            return true;
-        }
+        return mFeature.discard(arg);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 907069d..147f8d1 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -580,7 +580,11 @@
                             batteryStatsInternal);
             curDuration += curStart - lastUidBatteryUsageStartTs;
             try {
-                statsCommit.close();
+                if (statsCommit != null) {
+                    statsCommit.close();
+                } else {
+                    Slog.w(TAG, "Stat was null");
+                }
             } catch (IOException e) {
                 Slog.w(TAG, "Failed to close a stat");
             }
@@ -660,7 +664,11 @@
             }
         }
         try {
-            stats.close();
+            if (stats != null) {
+                stats.close();
+            } else {
+                Slog.w(TAG, "Stat was null");
+            }
         } catch (IOException e) {
             Slog.w(TAG, "Failed to close a stat");
         }
@@ -684,7 +692,11 @@
         final BatteryUsageStats stats = statsList.get(0);
         for (int i = 1; i < statsList.size(); i++) {
             try {
-                statsList.get(i).close();
+                if (statsList.get(i) != null) {
+                    statsList.get(i).close();
+                } else {
+                    Slog.w(TAG, "Stat was null");
+                }
             } catch (IOException e) {
                 Slog.w(TAG, "Failed to close a stat in BatteryUsageStats List");
             }
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 928b5d8..3cf4332 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1205,6 +1205,8 @@
             trackerMemFactor = mService.mProcessStats.getMemFactorLocked();
         }
 
+        mLastMemoryLevel = memFactor;
+        mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
         if (mService.mConstants.USE_MODERN_TRIM) {
             // Modern trim is not sent based on lowmem state
             // Dispatch UI_HIDDEN to processes that need it
@@ -1235,8 +1237,6 @@
             return false;
         }
 
-        mLastMemoryLevel = memFactor;
-        mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
         if (memFactor != ADJ_MEM_FACTOR_NORMAL) {
             if (mLowRamStartTime == 0) {
                 mLowRamStartTime = now;
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 5d31d15..e07c2bc 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -106,6 +106,14 @@
     private boolean mTimeoutScheduled;
 
     /**
+     * Snapshotted value of {@link ProcessRecord#getCpuDelayTime()}, typically
+     * used when deciding if we should extend the soft ANR timeout.
+     *
+     * Required when Flags.anrTimerServiceEnabled is false.
+     */
+    long lastCpuDelayTime;
+
+     /**
      * Snapshotted value of {@link ProcessStateRecord#getCurProcState()} before
      * dispatching the current broadcast to the receiver in this process.
      */
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index eb219a8..a428907 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -258,6 +258,9 @@
     private static final int MSG_PROCESS_FREEZABLE_CHANGED = 6;
     private static final int MSG_UID_STATE_CHANGED = 7;
 
+    // Required when Flags.anrTimerServiceEnabled is false.
+    private static final int MSG_DELIVERY_TIMEOUT_SOFT = 8;
+
     private void enqueueUpdateRunningList() {
         mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
         mLocalHandler.sendEmptyMessage(MSG_UPDATE_RUNNING_LIST);
@@ -271,6 +274,13 @@
                 updateRunningList();
                 return true;
             }
+            // Required when Flags.anrTimerServiceEnabled is false.
+            case MSG_DELIVERY_TIMEOUT_SOFT: {
+                synchronized (mService) {
+                    deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1);
+                    return true;
+                }
+            }
             case MSG_DELIVERY_TIMEOUT: {
                 deliveryTimeout((BroadcastProcessQueue) msg.obj);
                 return true;
@@ -1030,7 +1040,7 @@
             queue.setTimeoutScheduled(true);
             final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT
                     : mBgConstants.TIMEOUT);
-            mAnrTimer.start(queue, softTimeoutMillis);
+            startDeliveryTimeoutLocked(queue, softTimeoutMillis);
         } else {
             queue.setTimeoutScheduled(false);
         }
@@ -1110,7 +1120,7 @@
                 // If we were trying to deliver a manifest broadcast, throw the error as we need
                 // to try redelivering the broadcast to this receiver.
                 if (receiver instanceof ResolveInfo) {
-                    mAnrTimer.cancel(queue);
+                    cancelDeliveryTimeoutLocked(queue);
                     throw new BroadcastDeliveryFailedException(e);
                 }
                 finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
@@ -1159,6 +1169,41 @@
         r.resultTo = null;
     }
 
+    // Required when Flags.anrTimerServiceEnabled is false.
+    private void startDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue,
+            int softTimeoutMillis) {
+        if (mAnrTimer.serviceEnabled()) {
+            mAnrTimer.start(queue, softTimeoutMillis);
+        } else {
+            queue.lastCpuDelayTime = queue.app.getCpuDelayTime();
+            mLocalHandler.sendMessageDelayed(Message.obtain(mLocalHandler,
+                    MSG_DELIVERY_TIMEOUT_SOFT, softTimeoutMillis, 0, queue), softTimeoutMillis);
+        }
+    }
+
+    // Required when Flags.anrTimerServiceEnabled is false.
+    private void cancelDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue) {
+        mAnrTimer.cancel(queue);
+        if (!mAnrTimer.serviceEnabled()) {
+            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
+        }
+    }
+
+    // Required when Flags.anrTimerServiceEnabled is false.
+    private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue,
+            int softTimeoutMillis) {
+        if (queue.app != null) {
+            // Instead of immediately triggering an ANR, extend the timeout by
+            // the amount of time the process was runnable-but-waiting; we're
+            // only willing to do this once before triggering an hard ANR
+            final long cpuDelayTime = queue.app.getCpuDelayTime() - queue.lastCpuDelayTime;
+            final long hardTimeoutMillis = MathUtils.constrain(cpuDelayTime, 0, softTimeoutMillis);
+            mAnrTimer.start(queue, hardTimeoutMillis);
+        } else {
+            deliveryTimeoutLocked(queue);
+        }
+    }
+
     private void deliveryTimeout(@NonNull BroadcastProcessQueue queue) {
         synchronized (mService) {
             deliveryTimeoutLocked(queue);
@@ -1292,7 +1337,7 @@
                 mAnrTimer.discard(queue);
             }
         } else if (queue.timeoutScheduled()) {
-            mAnrTimer.cancel(queue);
+            cancelDeliveryTimeoutLocked(queue);
         }
 
         // Given that a receiver just finished, check if the "waitingFor" conditions are met.
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 4b622f5..903cb7b 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -175,13 +175,15 @@
                 TextFlags.ENABLE_NEW_CONTEXT_MENU_DEFAULT));
 
         // Register all text aconfig flags.
-        for (String flag : TextFlags.TEXT_ACONFIGS_FLAGS) {
+        for (int i = 0; i < TextFlags.TEXT_ACONFIGS_FLAGS.length; i++) {
+            final String flag = TextFlags.TEXT_ACONFIGS_FLAGS[i];
+            final boolean defaultValue = TextFlags.TEXT_ACONFIG_DEFAULT_VALUE[i];
             sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
                     TextFlags.NAMESPACE,
                     flag,
                     TextFlags.getKeyForFlag(flag),
                     boolean.class,
-                    false));  // All aconfig flags are false by default.
+                    defaultValue));
         }
         // add other device configs here...
     }
diff --git a/services/core/java/com/android/server/am/OomConnection.java b/services/core/java/com/android/server/am/OomConnection.java
new file mode 100644
index 0000000..17a4ce5
--- /dev/null
+++ b/services/core/java/com/android/server/am/OomConnection.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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.am;
+
+import android.os.OomKillRecord;
+import android.util.Slog;
+
+/** Connection to the out-of-memory (OOM) events' file */
+public final class OomConnection {
+    private static final String TAG = "OomConnection";
+
+    /** Connection listener interface */
+    public interface OomConnectionListener {
+
+        /**
+         * Callback function to handle the newest OOM kills.
+         *
+         * @param oomKills List of oom kills received from `waitOom()`
+         */
+        void handleOomEvent(OomKillRecord[] oomKills);
+    }
+
+    private final OomConnectionListener mOomListener;
+
+    private final OomConnectionThread mOomConnectionThread;
+
+    private static native OomKillRecord[] waitOom();
+
+    public OomConnection(OomConnectionListener listener) {
+        mOomListener = listener;
+        mOomConnectionThread = new OomConnectionThread();
+        mOomConnectionThread.start();
+    }
+
+    private final class OomConnectionThread extends Thread {
+        public void run() {
+            while (true) {
+                OomKillRecord[] oom_kills = null;
+                try {
+                    oom_kills = waitOom();
+                    mOomListener.handleOomEvent(oom_kills);
+                } catch (RuntimeException e) {
+                    Slog.e(TAG, "failed waiting for OOM events: " + e);
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a97675f..4572766 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -97,6 +97,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.OomKillRecord;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -412,6 +413,8 @@
 
     private static LmkdConnection sLmkdConnection = null;
 
+    private static OomConnection sOomConnection = null;
+
     private boolean mOomLevelsSet = false;
 
     private boolean mAppDataIsolationEnabled = false;
@@ -855,6 +858,21 @@
                     THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
             sKillThread.start();
             sKillHandler = new KillHandler(sKillThread.getLooper());
+            sOomConnection = new OomConnection(new OomConnection.OomConnectionListener() {
+                @Override
+                public void handleOomEvent(OomKillRecord[] oomKills) {
+                    for (OomKillRecord oomKill: oomKills) {
+                        synchronized (mProcLock) {
+                            noteAppKill(
+                                oomKill.getPid(),
+                                oomKill.getUid(),
+                                ApplicationExitInfo.REASON_LOW_MEMORY,
+                                ApplicationExitInfo.SUBREASON_OOM_KILL,
+                                "oom");
+                        }
+                    }
+                }
+            });
             sLmkdConnection = new LmkdConnection(sKillThread.getLooper().getQueue(),
                     new LmkdConnection.LmkdConnectionListener() {
                         @Override
diff --git a/services/core/java/com/android/server/am/ProcessProfileRecord.java b/services/core/java/com/android/server/am/ProcessProfileRecord.java
index db74f1a..c1f86e0 100644
--- a/services/core/java/com/android/server/am/ProcessProfileRecord.java
+++ b/services/core/java/com/android/server/am/ProcessProfileRecord.java
@@ -142,6 +142,11 @@
     final AtomicLong mCurCpuTime = new AtomicLong(0);
 
     /**
+     * How long the process has spent on waiting in the runqueue since fork.
+     */
+    final AtomicLong mLastCpuDelayTime = new AtomicLong(0);
+
+    /**
      * Last selected memory trimming level.
      */
     @CompositeRWLock({"mService", "mProcLock"})
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index d8a2695..3771c05 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1255,11 +1255,10 @@
             killProcessGroup = true;
         }
         if (killProcessGroup) {
-            if (async) {
-                ProcessList.killProcessGroup(uid, mPid);
-            } else {
+            if (!async) {
                 Process.sendSignalToProcessGroup(uid, mPid, OsConstants.SIGKILL);
             }
+            ProcessList.killProcessGroup(uid, mPid);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 4a0bc4b..1ba1f55 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -131,13 +131,17 @@
         "car_telemetry",
         "codec_fwk",
         "companion",
+        "content_protection",
         "context_hub",
         "core_experiments_team_internal",
         "core_graphics",
         "haptics",
         "hardware_backed_security_mainline",
+        "input",
         "machine_learning",
+        "mainline_sdk",
         "media_audio",
+        "media_drm",
         "media_solutions",
         "nfc",
         "pixel_audio_android",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index b03cc62..26d99d8 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -6,4 +6,12 @@
     description: "Utilize new OomAdjuster implementation"
     bug: "298055811"
     is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+     name: "anr_timer_service_enabled"
+     namespace: "system_performance"
+     is_fixed_read_only: true
+     description: "Feature flag for the ANR timer service"
+     bug: "282428924"
+}
diff --git a/services/core/java/com/android/server/audio/AudioManagerShellCommand.java b/services/core/java/com/android/server/audio/AudioManagerShellCommand.java
index 241abaf..85acf70 100644
--- a/services/core/java/com/android/server/audio/AudioManagerShellCommand.java
+++ b/services/core/java/com/android/server/audio/AudioManagerShellCommand.java
@@ -47,6 +47,12 @@
                 return setEncodedSurroundMode();
             case "get-encoded-surround-mode":
                 return getEncodedSurroundMode();
+            case "set-sound-dose-value":
+                return setSoundDoseValue();
+            case "get-sound-dose-value":
+                return getSoundDoseValue();
+            case "reset-sound-dose-timeout":
+                return resetSoundDoseTimeout();
         }
         return 0;
     }
@@ -66,6 +72,12 @@
         pw.println("    Sets the encoded surround sound mode to SURROUND_SOUND_MODE");
         pw.println("  get-encoded-surround-mode");
         pw.println("    Returns the encoded surround sound mode");
+        pw.println("  set-sound-dose-value");
+        pw.println("    Sets the current sound dose value");
+        pw.println("  get-sound-dose-value");
+        pw.println("    Returns the current sound dose value");
+        pw.println("  reset-sound-dose-timeout");
+        pw.println("    Resets the sound dose timeout used for momentary exposure");
     }
 
     private int setSurroundFormatEnabled() {
@@ -162,4 +174,46 @@
         getOutPrintWriter().println("Encoded surround mode: " + am.getEncodedSurroundMode());
         return 0;
     }
+
+    private int setSoundDoseValue() {
+        String soundDoseValueText = getNextArg();
+
+        if (soundDoseValueText == null) {
+            getErrPrintWriter().println("Error: no sound dose value specified");
+            return 1;
+        }
+
+        float soundDoseValue = 0.f;
+        try {
+            soundDoseValue = Float.parseFloat(soundDoseValueText);
+        } catch (NumberFormatException e) {
+            getErrPrintWriter().println("Error: wrong format specified for sound dose");
+            return 1;
+        }
+
+        if (soundDoseValue < 0) {
+            getErrPrintWriter().println("Error: invalid value of sound dose");
+            return 1;
+        }
+
+        final Context context = mService.mContext;
+        final AudioManager am = context.getSystemService(AudioManager.class);
+        am.setCsd(soundDoseValue);
+        return 0;
+    }
+
+    private int getSoundDoseValue() {
+        final Context context = mService.mContext;
+        final AudioManager am = context.getSystemService(AudioManager.class);
+        getOutPrintWriter().println("Sound dose value: " + am.getCsd());
+        return 0;
+    }
+
+    private int resetSoundDoseTimeout() {
+        final Context context = mService.mContext;
+        final AudioManager am = context.getSystemService(AudioManager.class);
+        am.setCsd(-1.f);
+        getOutPrintWriter().println("Reset sound dose momentary exposure timeout");
+        return 0;
+    }
 }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0aa9cc1..3243385 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -36,7 +36,6 @@
 import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
 import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
 import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
-
 import static com.android.server.audio.SoundDoseHelper.ACTION_CHECK_MUSIC_ACTIVE;
 import static com.android.server.utils.EventLogger.Event.ALOGE;
 import static com.android.server.utils.EventLogger.Event.ALOGI;
@@ -73,7 +72,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -267,6 +265,8 @@
     private final SettingsAdapter mSettings;
     private final AudioPolicyFacade mAudioPolicy;
 
+    private final MusicFxHelper mMusicFxHelper;
+
     /** Debug audio mode */
     protected static final boolean DEBUG_MODE = false;
 
@@ -407,9 +407,15 @@
     private static final int MSG_CONFIGURATION_CHANGED = 54;
     private static final int MSG_BROADCAST_MASTER_MUTE = 55;
 
-    /** Messages handled by the {@link SoundDoseHelper}. */
+    /**
+     * Messages handled by the {@link SoundDoseHelper}, do not exceed
+     * {@link MUSICFX_HELPER_MSG_START}.
+     */
     /*package*/ static final int SAFE_MEDIA_VOLUME_MSG_START = 1000;
 
+    /** Messages handled by the {@link MusicFxHelper}. */
+    /*package*/ static final int MUSICFX_HELPER_MSG_START = 1100;
+
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -1304,6 +1310,8 @@
                 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */);
 
         mDisplayManager = context.getSystemService(DisplayManager.class);
+
+        mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler);
     }
 
     private void initVolumeStreamStates() {
@@ -9456,11 +9464,21 @@
                     onConfigurationChanged();
                     break;
 
+                case MusicFxHelper.MSG_EFFECT_CLIENT_GONE:
+                    mMusicFxHelper.handleMessage(msg);
+                    break;
+
+                case SoundDoseHelper.MSG_CONFIGURE_SAFE_MEDIA:
+                case SoundDoseHelper.MSG_CONFIGURE_SAFE_MEDIA_FORCED:
+                case SoundDoseHelper.MSG_PERSIST_SAFE_VOLUME_STATE:
+                case SoundDoseHelper.MSG_PERSIST_MUSIC_ACTIVE_MS:
+                case SoundDoseHelper.MSG_PERSIST_CSD_VALUES:
+                case SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION:
+                    mSoundDoseHelper.handleMessage(msg);
+                    break;
+
                 default:
-                    if (msg.what >= SAFE_MEDIA_VOLUME_MSG_START) {
-                        // msg could be for the SoundDoseHelper
-                        mSoundDoseHelper.handleMessage(msg);
-                    }
+                    Log.e(TAG, "Unsupported msgId " + msg.what);
             }
         }
     }
@@ -9695,7 +9713,7 @@
                 }
             } else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) ||
                     action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) {
-                handleAudioEffectBroadcast(context, intent);
+                mMusicFxHelper.handleAudioEffectBroadcast(context, intent);
             } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
                 final int[] suspendedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
                 final String[] suspendedPackages =
@@ -9750,27 +9768,6 @@
         }
     } // end class AudioServiceUserRestrictionsListener
 
-    private void handleAudioEffectBroadcast(Context context, Intent intent) {
-        String target = intent.getPackage();
-        if (target != null) {
-            Log.w(TAG, "effect broadcast already targeted to " + target);
-            return;
-        }
-        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
-        // TODO this should target a user-selected panel
-        List<ResolveInfo> ril = context.getPackageManager().queryBroadcastReceivers(
-                intent, 0 /* flags */);
-        if (ril != null && ril.size() != 0) {
-            ResolveInfo ri = ril.get(0);
-            if (ri != null && ri.activityInfo != null && ri.activityInfo.packageName != null) {
-                intent.setPackage(ri.activityInfo.packageName);
-                context.sendBroadcastAsUser(intent, UserHandle.ALL);
-                return;
-            }
-        }
-        Log.w(TAG, "couldn't find receiver package for effect intent");
-    }
-
     private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
         PackageManager pm = mContext.getPackageManager();
         // Find the home activity of the user. It should not be killed to avoid expensive restart,
diff --git a/services/core/java/com/android/server/audio/MusicFxHelper.java b/services/core/java/com/android/server/audio/MusicFxHelper.java
new file mode 100644
index 0000000..6c0fef5
--- /dev/null
+++ b/services/core/java/com/android/server/audio/MusicFxHelper.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2023 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.audio;
+
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static com.android.server.audio.AudioService.MUSICFX_HELPER_MSG_START;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.IUidObserver;
+import android.app.UidObserver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.media.AudioManager;
+import android.media.audiofx.AudioEffect;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.audio.AudioService.AudioHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * MusicFx management.
+ * .
+ */
+public class MusicFxHelper {
+    private static final String TAG = "AS.MusicFxHelper";
+
+    @NonNull private final Context mContext;
+
+    @NonNull private final AudioHandler mAudioHandler;
+
+    // Synchronization UidSessionMap access between UidObserver and AudioServiceBroadcastReceiver.
+    private final Object mClientUidMapLock = new Object();
+
+    // The binder token identifying the UidObserver registration.
+    private IBinder mUidObserverToken = null;
+
+    // Hashmap of UID and list of open sessions for this UID.
+    @GuardedBy("mClientUidMapLock")
+    private SparseArray<List<Integer>> mClientUidSessionMap = new SparseArray<>();
+
+    /*package*/ static final int MSG_EFFECT_CLIENT_GONE = MUSICFX_HELPER_MSG_START + 1;
+
+    // UID observer for effect MusicFx clients
+    private final IUidObserver mEffectUidObserver = new UidObserver() {
+        @Override public void onUidGone(int uid, boolean disabled) {
+            Log.w(TAG, " send MSG_EFFECT_CLIENT_GONE");
+            mAudioHandler.sendMessageAtTime(
+                    mAudioHandler.obtainMessage(MSG_EFFECT_CLIENT_GONE,
+                            uid /* arg1 */, 0 /* arg2 */,
+                            null /* obj */), 0 /* delay */);
+        }
+    };
+
+    // BindService connection implementation, we don't need any implementation now
+    private ServiceConnection mMusicFxBindConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.d(TAG, " service connected to " + name);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Log.d(TAG, " service disconnected from " + name);
+        }
+    };
+
+    MusicFxHelper(@NonNull Context context, @NonNull AudioHandler audioHandler) {
+        mContext = context;
+        mAudioHandler = audioHandler;
+    }
+
+    /**
+     * Handle the broadcast {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
+     * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
+     *
+     * If the intent is {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION}:
+     *  - If the MusicFx process is not running, call bindService with AUTO_CREATE to create.
+     *  - If this is the first audio session in MusicFx, call set foreground service delegate.
+     *  - If this is the first audio session for a given UID, add the UID into observer.
+     *
+     * If the intent is {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION}:
+     *  - MusicFx will not be foreground delegated anymore.
+     *  - The KeepAliveService of MusicFx will be unbound.
+     *  - The UidObserver will be removed.
+     */
+    public void handleAudioEffectBroadcast(Context context, Intent intent) {
+        String target = intent.getPackage();
+        if (target != null) {
+            Log.w(TAG, "effect broadcast already targeted to " + target);
+            return;
+        }
+        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+        final PackageManager pm = context.getPackageManager();
+        // TODO this should target a user-selected panel
+        List<ResolveInfo> ril = pm.queryBroadcastReceivers(intent, 0 /* flags */);
+        if (ril != null && ril.size() != 0) {
+            ResolveInfo ri = ril.get(0);
+            final String senderPackageName = intent.getStringExtra(AudioEffect.EXTRA_PACKAGE_NAME);
+            try {
+                final int senderUid = pm.getPackageUidAsUser(senderPackageName,
+                        PackageManager.PackageInfoFlags.of(MATCH_ANY_USER), getCurrentUserId());
+                if (ri != null && ri.activityInfo != null && ri.activityInfo.packageName != null) {
+                    intent.setPackage(ri.activityInfo.packageName);
+                    synchronized (mClientUidMapLock) {
+                        setMusicFxServiceWithObserver(context, intent, senderUid);
+                    }
+                    context.sendBroadcastAsUser(intent, UserHandle.ALL);
+                    return;
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "Not able to find UID from package: " + senderPackageName + " error: "
+                        + e);
+            }
+        }
+        Log.w(TAG, "couldn't find receiver package for effect intent");
+    }
+
+    /**
+     * Handle the UidObserver onUidGone callback of MusicFx clients.
+     * All open audio sessions of this UID will be closed.
+     * If this is the last UID for MusicFx:
+     *  - MusicFx will not be foreground delegated anymore.
+     *  - The KeepAliveService of MusicFx will be unbound.
+     *  - The UidObserver will be removed.
+     */
+    public void handleEffectClientUidGone(int uid) {
+        synchronized (mClientUidMapLock) {
+            Log.w(TAG, " inside handle MSG_EFFECT_CLIENT_GONE");
+            // Once the uid is no longer running, close all remain audio session(s) for this UID
+            if (mClientUidSessionMap.get(Integer.valueOf(uid)) != null) {
+                final List<Integer> sessions = mClientUidSessionMap.get(Integer.valueOf(uid));
+                Log.i(TAG, "UID " + uid + " gone, closing " + sessions.size() + " sessions");
+                for (Integer session : sessions) {
+                    Intent intent = new Intent(
+                            AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
+                    intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, session);
+                    setMusicFxServiceWithObserver(mContext, intent, uid);
+                    Log.i(TAG, "Close session " + session + " of UID " + uid);
+                }
+                mClientUidSessionMap.remove(Integer.valueOf(uid));
+            }
+        }
+    }
+
+    @GuardedBy("mClientUidMapLock")
+    private void setMusicFxServiceWithObserver(Context context, Intent intent, int senderUid) {
+        PackageManager pm = context.getPackageManager();
+        try {
+            final int audioSession = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION,
+                    AudioManager.AUDIO_SESSION_ID_GENERATE);
+            if (AudioManager.AUDIO_SESSION_ID_GENERATE == audioSession) {
+                Log.e(TAG, "Intent missing audio session: " + audioSession);
+                return;
+            }
+
+            // only apply to com.android.musicfx and KeepAliveService for now
+            final String musicFxPackageName = "com.android.musicfx";
+            final String musicFxKeepAliveService = "com.android.musicfx.KeepAliveService";
+            final int musicFxUid = pm.getPackageUidAsUser(musicFxPackageName,
+                    PackageManager.PackageInfoFlags.of(MATCH_ANY_USER), getCurrentUserId());
+
+            if (intent.getAction().equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)) {
+                List<Integer> sessions = new ArrayList<>();
+                Log.d(TAG, "UID " + senderUid + ", open MusicFx session " + audioSession);
+                // start foreground service delegate and register UID observer with the first
+                // session of first UID open
+                if (0 == mClientUidSessionMap.size()) {
+                    final int procState = ActivityManager.getService().getPackageProcessState(
+                            musicFxPackageName, this.getClass().getPackage().getName());
+                    // if musicfx process not in binding state, call bindService with AUTO_CREATE
+                    if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+                        Intent bindIntent = new Intent().setClassName(musicFxPackageName,
+                                musicFxKeepAliveService);
+                        context.bindServiceAsUser(
+                                bindIntent, mMusicFxBindConnection, Context.BIND_AUTO_CREATE,
+                                UserHandle.of(getCurrentUserId()));
+                        Log.i(TAG, "bindService to " + musicFxPackageName);
+                    }
+
+                    Log.i(TAG, "Package " + musicFxPackageName + " uid " + musicFxUid
+                            + " procState " + procState);
+                } else if (mClientUidSessionMap.get(Integer.valueOf(senderUid)) != null) {
+                    sessions = mClientUidSessionMap.get(Integer.valueOf(senderUid));
+                    if (sessions.contains(audioSession)) {
+                        Log.e(TAG, "Audio session " + audioSession + " already exist for UID "
+                                + senderUid + ", abort");
+                        return;
+                    }
+                }
+                // first session of this UID
+                if (sessions.size() == 0) {
+                    // call registerUidObserverForUids with the first UID and first session
+                    if (mClientUidSessionMap.size() == 0 || mUidObserverToken == null) {
+                        mUidObserverToken = ActivityManager.getService().registerUidObserverForUids(
+                                mEffectUidObserver, ActivityManager.UID_OBSERVER_GONE,
+                                ActivityManager.PROCESS_STATE_UNKNOWN, null, new int[]{senderUid});
+                        Log.i(TAG, "UID " + senderUid + " registered to observer");
+                    } else {
+                        // add UID to observer for each new UID
+                        ActivityManager.getService().addUidToObserver(mUidObserverToken, TAG,
+                                senderUid);
+                        Log.i(TAG, "UID " + senderUid + " addeded to observer");
+                    }
+                }
+
+                sessions.add(Integer.valueOf(audioSession));
+                mClientUidSessionMap.put(Integer.valueOf(senderUid), sessions);
+            } else {
+                if (mClientUidSessionMap.get(senderUid) != null) {
+                    Log.d(TAG, "UID " + senderUid + ", close MusicFx session " + audioSession);
+                    List<Integer> sessions = mClientUidSessionMap.get(Integer.valueOf(senderUid));
+                    sessions.remove(Integer.valueOf(audioSession));
+                    if (0 == sessions.size()) {
+                        mClientUidSessionMap.remove(Integer.valueOf(senderUid));
+                    } else {
+                        mClientUidSessionMap.put(Integer.valueOf(senderUid), sessions);
+                    }
+
+                    // stop foreground service delegate and unregister UID observer with the
+                    // last session of last UID close
+                    if (0 == mClientUidSessionMap.size()) {
+                        ActivityManager.getService().unregisterUidObserver(mEffectUidObserver);
+                        mClientUidSessionMap.clear();
+                        context.unbindService(mMusicFxBindConnection);
+                        Log.i(TAG, " remove all sessions, unregister UID observer, and unbind "
+                                + musicFxPackageName);
+                    }
+                } else {
+                    // if the audio session already closed, print an error
+                    Log.e(TAG, "UID " + senderUid + " close audio session " + audioSession
+                            + " which does not exist");
+                }
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "Not able to find UID from package: " + e);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException " + e + " with handling intent");
+        }
+    }
+
+    private int getCurrentUserId() {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            UserInfo currentUser = ActivityManager.getService().getCurrentUser();
+            return currentUser.id;
+        } catch (RemoteException e) {
+            // Activity manager not running, nothing we can do assume user 0.
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        return UserHandle.USER_SYSTEM;
+    }
+
+    /*package*/ void handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_EFFECT_CLIENT_GONE:
+                Log.w(TAG, " handle MSG_EFFECT_CLIENT_GONE");
+                handleEffectClientUidGone(msg.arg1 /* uid */);
+                break;
+            default:
+                Log.e(TAG, "Unexpected msg to handle in MusicFxHelper: " + msg.what);
+                break;
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 81365bf..6c5f3e7 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -108,11 +108,11 @@
     private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
     private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
 
-    private static final int MSG_CONFIGURE_SAFE_MEDIA = SAFE_MEDIA_VOLUME_MSG_START + 1;
-    private static final int MSG_CONFIGURE_SAFE_MEDIA_FORCED = SAFE_MEDIA_VOLUME_MSG_START + 2;
-    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = SAFE_MEDIA_VOLUME_MSG_START + 3;
-    private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = SAFE_MEDIA_VOLUME_MSG_START + 4;
-    private static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 5;
+    /*package*/ static final int MSG_CONFIGURE_SAFE_MEDIA = SAFE_MEDIA_VOLUME_MSG_START + 1;
+    /*package*/ static final int MSG_CONFIGURE_SAFE_MEDIA_FORCED = SAFE_MEDIA_VOLUME_MSG_START + 2;
+    /*package*/ static final int MSG_PERSIST_SAFE_VOLUME_STATE = SAFE_MEDIA_VOLUME_MSG_START + 3;
+    /*package*/ static final int MSG_PERSIST_MUSIC_ACTIVE_MS = SAFE_MEDIA_VOLUME_MSG_START + 4;
+    /*package*/ static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 5;
     /*package*/ static final int MSG_CSD_UPDATE_ATTENUATION = SAFE_MEDIA_VOLUME_MSG_START + 6;
 
     private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index f74b45c..e42b664 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -875,6 +875,10 @@
     public void simulateVhalFingerDown(int userId, int sensorId) {
         Slog.d(getTag(), "Simulate virtual HAL finger down event");
         final AidlSession session = mFingerprintSensors.get(sensorId).getSessionForUser(userId);
+        if (session == null) {
+            Slog.e(getTag(), "no existing hal session found - aborting");
+            return;
+        }
         final PointerContext pc = new PointerContext();
         try {
             session.getSession().onPointerDownWithContext(pc);
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 9805fd3..333f62a 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1845,7 +1845,7 @@
     private void parseListenForTickles(TypedXmlPullParser parser) {
         int userId = 0;
         try {
-            parser.getAttributeInt(null, XML_ATTR_USER);
+            userId = parser.getAttributeInt(null, XML_ATTR_USER);
         } catch (XmlPullParserException e) {
             Slog.e(TAG, "error parsing the user for listen-for-tickles", e);
         }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 9e92c8d..cfbe0c6 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -60,6 +60,9 @@
 import com.android.server.display.config.NitsMap;
 import com.android.server.display.config.NonNegativeFloatToFloatPoint;
 import com.android.server.display.config.Point;
+import com.android.server.display.config.PowerThrottlingConfig;
+import com.android.server.display.config.PowerThrottlingMap;
+import com.android.server.display.config.PowerThrottlingPoint;
 import com.android.server.display.config.PredefinedBrightnessLimitNames;
 import com.android.server.display.config.RefreshRateConfigs;
 import com.android.server.display.config.RefreshRateRange;
@@ -139,6 +142,30 @@
  *      </screenBrightnessMap>
  *
  *      <screenBrightnessDefault>0.65</screenBrightnessDefault>
+ *      <powerThrottlingConfig>
+ *        <brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>
+ *        <pollingWindowMillis>15</pollingWindowMillis>
+ *          <powerThrottlingMap>
+ *              <powerThrottlingPoint>
+ *                  <thermalStatus>severe</thermalStatus>
+ *                  <powerQuotaMilliWatts>200.6</powerQuotaMilliWatts>
+ *              </powerThrottlingPoint>
+ *              <powerThrottlingPoint>
+ *                  <thermalStatus>critical</thermalStatus>
+ *                  <powerQuotaMilliWatts>300</powerQuotaMilliWatts>
+ *              </powerThrottlingPoint>
+ *          </powerThrottlingMap>
+ *          <powerThrottlingMap id="id_2"> // optional attribute, leave blank for default
+ *             <powerThrottlingPoint>
+ *                 <thermalStatus>moderate</thermalStatus>
+ *                 <powerQuotaMilliWatts>400</powerQuotaMilliWatts>
+ *             </powerThrottlingPoint>
+ *             <powerThrottlingPoint>
+ *                 <thermalStatus>severe</thermalStatus>
+ *                 <powerQuotaMilliWatts>250</powerQuotaMilliWatts>
+ *            </powerThrottlingPoint>
+ *          </powerThrottlingMap>
+ *      </powerThrottlingConfig>
  *
  *      <thermalThrottling>
  *        <brightnessThrottlingMap>
@@ -669,6 +696,8 @@
     private List<String> mQuirks;
     private boolean mIsHighBrightnessModeEnabled = false;
     private HighBrightnessModeData mHbmData;
+    @Nullable
+    private PowerThrottlingConfigData mPowerThrottlingConfigData;
     private DensityMapping mDensityMapping;
     private String mLoadedFrom = null;
     private Spline mSdrToHdrRatioSpline;
@@ -781,6 +810,9 @@
     private final HashMap<String, ThermalBrightnessThrottlingData>
             mThermalBrightnessThrottlingDataMapByThrottlingId = new HashMap<>();
 
+    private final HashMap<String, PowerThrottlingData>
+            mPowerThrottlingDataMapByThrottlingId = new HashMap<>();
+
     private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>>
             mRefreshRateThrottlingMap = new HashMap<>();
 
@@ -1458,6 +1490,14 @@
         return hbmData;
     }
 
+    /**
+     * @return Power throttling configuration data for the display.
+     */
+    @Nullable
+    public PowerThrottlingConfigData getPowerThrottlingConfigData() {
+        return mPowerThrottlingConfigData;
+    }
+
     @NonNull
     public Map<BrightnessLimitMapType, Map<Float, Float>> getLuxThrottlingData() {
         return mLuxThrottlingData;
@@ -1491,6 +1531,14 @@
     }
 
     /**
+     * @return power throttling configuration data for this display, for each throttling id.
+     **/
+    public HashMap<String, PowerThrottlingData>
+            getPowerThrottlingDataMapByThrottlingId() {
+        return mPowerThrottlingDataMapByThrottlingId;
+    }
+
+    /**
      * @return Auto brightness darkening light debounce
      */
     public long getAutoBrightnessDarkeningLightDebounce() {
@@ -1702,6 +1750,9 @@
                 + ", mThermalBrightnessThrottlingDataMapByThrottlingId="
                 + mThermalBrightnessThrottlingDataMapByThrottlingId
                 + "\n"
+                + ", mPowerThrottlingDataMapByThrottlingId="
+                + mPowerThrottlingDataMapByThrottlingId
+                + "\n"
                 + "mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
                 + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
                 + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
@@ -1853,6 +1904,7 @@
                 loadBrightnessConstraintsFromConfigXml();
                 loadBrightnessMap(config);
                 loadThermalThrottlingConfig(config);
+                loadPowerThrottlingConfigData(config);
                 loadHighBrightnessModeData(config);
                 loadLuxThrottling(config);
                 loadQuirks(config);
@@ -2171,6 +2223,59 @@
         }
     }
 
+    private boolean loadPowerThrottlingMaps(PowerThrottlingConfig throttlingConfig) {
+        final List<PowerThrottlingMap> maps = throttlingConfig.getPowerThrottlingMap();
+        if (maps == null || maps.isEmpty()) {
+            Slog.i(TAG, "No power throttling map found");
+            return false;
+        }
+
+        for (PowerThrottlingMap map : maps) {
+            final List<PowerThrottlingPoint> points = map.getPowerThrottlingPoint();
+            // At least 1 point is guaranteed by the display device config schema
+            List<PowerThrottlingData.ThrottlingLevel> throttlingLevels =
+                    new ArrayList<>(points.size());
+
+            boolean badConfig = false;
+            for (PowerThrottlingPoint point : points) {
+                ThermalStatus status = point.getThermalStatus();
+                if (!thermalStatusIsValid(status)) {
+                    badConfig = true;
+                    break;
+                }
+
+                throttlingLevels.add(new PowerThrottlingData.ThrottlingLevel(
+                        convertThermalStatus(status),
+                            point.getPowerQuotaMilliWatts().floatValue()));
+            }
+
+            if (!badConfig) {
+                String id = map.getId() == null ? DEFAULT_ID : map.getId();
+                if (mPowerThrottlingDataMapByThrottlingId.containsKey(id)) {
+                    throw new RuntimeException("Power throttling data with ID " + id
+                            + " already exists");
+                }
+                mPowerThrottlingDataMapByThrottlingId.put(id,
+                        PowerThrottlingData.create(throttlingLevels));
+            }
+        }
+        return true;
+    }
+
+    private void loadPowerThrottlingConfigData(DisplayConfiguration config) {
+        final PowerThrottlingConfig powerThrottlingCfg = config.getPowerThrottlingConfig();
+        if (powerThrottlingCfg == null) {
+            return;
+        }
+        if (!loadPowerThrottlingMaps(powerThrottlingCfg)) {
+            return;
+        }
+        float lowestBrightnessCap = powerThrottlingCfg.getBrightnessLowestCapAllowed().floatValue();
+        int pollingWindowMillis = powerThrottlingCfg.getPollingWindowMillis().intValue();
+        mPowerThrottlingConfigData = new PowerThrottlingConfigData(lowestBrightnessCap,
+                                                                   pollingWindowMillis);
+    }
+
     private void loadRefreshRateSetting(DisplayConfiguration config) {
         final RefreshRateConfigs refreshRateConfigs =
                 (config == null) ? null : config.getRefreshRate();
@@ -3379,6 +3484,148 @@
     }
 
     /**
+     * Container for Power throttling configuration data.
+     * TODO(b/302814899): extract to separate class.
+     */
+    public static class PowerThrottlingConfigData {
+        /** Lowest brightness cap allowed for this device. */
+        public final float brightnessLowestCapAllowed;
+        /** Time window for polling power in seconds. */
+        public final int pollingWindowMillis;
+        public PowerThrottlingConfigData(float brightnessLowestCapAllowed,
+                int pollingWindowMillis) {
+            this.brightnessLowestCapAllowed = brightnessLowestCapAllowed;
+            this.pollingWindowMillis = pollingWindowMillis;
+        }
+
+        @Override
+        public String toString() {
+            return "PowerThrottlingConfigData{"
+                    + "brightnessLowestCapAllowed: "
+                    + brightnessLowestCapAllowed
+                    + ", pollingWindowMillis: " + pollingWindowMillis
+                    + "} ";
+        }
+    }
+
+    /**
+     * Container for power throttling data.
+     * TODO(b/302814899): extract to separate class and unify with ThermalBrightnessThrottlingData.
+     */
+    public static class PowerThrottlingData {
+        public List<ThrottlingLevel> throttlingLevels;
+
+        /**
+         * thermal status to power quota mapping.
+         */
+        public static class ThrottlingLevel {
+            public @PowerManager.ThermalStatus int thermalStatus;
+            public float powerQuotaMilliWatts;
+
+            public ThrottlingLevel(
+                    @PowerManager.ThermalStatus int thermalStatus, float powerQuotaMilliWatts) {
+                this.thermalStatus = thermalStatus;
+                this.powerQuotaMilliWatts = powerQuotaMilliWatts;
+            }
+
+            @Override
+            public String toString() {
+                return "[" + thermalStatus + "," + powerQuotaMilliWatts + "]";
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (!(obj instanceof ThrottlingLevel)) {
+                    return false;
+                }
+                ThrottlingLevel otherThrottlingLevel = (ThrottlingLevel) obj;
+
+                return otherThrottlingLevel.thermalStatus == this.thermalStatus
+                        && otherThrottlingLevel.powerQuotaMilliWatts == this.powerQuotaMilliWatts;
+            }
+
+            @Override
+            public int hashCode() {
+                int result = 1;
+                result = 31 * result + thermalStatus;
+                result = 31 * result + Float.hashCode(powerQuotaMilliWatts);
+                return result;
+            }
+        }
+
+
+        /**
+         * Creates multiple temperature based throttling levels of power quota.
+         */
+        public static PowerThrottlingData create(
+                List<ThrottlingLevel> throttlingLevels) {
+            if (throttlingLevels == null || throttlingLevels.size() == 0) {
+                Slog.e(TAG, "PowerThrottlingData received null or empty throttling levels");
+                return null;
+            }
+
+            ThrottlingLevel prevLevel = throttlingLevels.get(0);
+            final int numLevels = throttlingLevels.size();
+            for (int i = 1; i < numLevels; i++) {
+                ThrottlingLevel thisLevel = throttlingLevels.get(i);
+
+                if (thisLevel.thermalStatus <= prevLevel.thermalStatus) {
+                    Slog.e(TAG, "powerThrottlingMap must be strictly increasing, ignoring "
+                            + "configuration. ThermalStatus " + thisLevel.thermalStatus + " <= "
+                            + prevLevel.thermalStatus);
+                    return null;
+                }
+
+                if (thisLevel.powerQuotaMilliWatts >= prevLevel.powerQuotaMilliWatts) {
+                    Slog.e(TAG, "powerThrottlingMap must be strictly decreasing, ignoring "
+                            + "configuration. powerQuotaMilliWatts "
+                            + thisLevel.powerQuotaMilliWatts + " >= "
+                            + prevLevel.powerQuotaMilliWatts);
+                    return null;
+                }
+
+                prevLevel = thisLevel;
+            }
+            return new PowerThrottlingData(throttlingLevels);
+        }
+
+        @Override
+        public String toString() {
+            return "PowerThrottlingData{"
+                    + "throttlingLevels:" + throttlingLevels
+                    + "} ";
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+
+            if (!(obj instanceof PowerThrottlingData)) {
+                return false;
+            }
+
+            PowerThrottlingData otherData = (PowerThrottlingData) obj;
+            return throttlingLevels.equals(otherData.throttlingLevels);
+        }
+
+        @Override
+        public int hashCode() {
+            return throttlingLevels.hashCode();
+        }
+
+        @VisibleForTesting
+        PowerThrottlingData(List<ThrottlingLevel> inLevels) {
+            throttlingLevels = new ArrayList<>(inLevels.size());
+            for (ThrottlingLevel level : inLevels) {
+                throttlingLevels.add(new ThrottlingLevel(level.thermalStatus,
+                        level.powerQuotaMilliWatts));
+            }
+        }
+    }
+
+    /**
      * Container for brightness throttling data.
      */
     public static class ThermalBrightnessThrottlingData {
diff --git a/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java b/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java
index 652e6cf..39f0b13 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java
@@ -105,16 +105,21 @@
     public void resetHdrConfig(HdrBrightnessData data, int width, int height,
             float minimumHdrPercentOfScreen, IBinder displayToken) {
         mHdrBrightnessData = data;
-        mHdrListener.mHdrMinPixels = (float) (width * height) * minimumHdrPercentOfScreen;
+        mHdrListener.mHdrMinPixels = minimumHdrPercentOfScreen <= 0 ? -1
+                : (float) (width * height) * minimumHdrPercentOfScreen;
         if (displayToken != mRegisteredDisplayToken) { // token changed, resubscribe
             if (mRegisteredDisplayToken != null) { // previous token not null, unsubscribe
                 mHdrListener.unregister(mRegisteredDisplayToken);
                 mHdrVisible = false;
+                mRegisteredDisplayToken = null;
             }
-            if (displayToken != null) { // new token not null, subscribe
+            // new token not null and hdr min % of the screen is set, subscribe.
+            // e.g. for virtual display, HBM data will be missing and HdrListener
+            // should not be registered
+            if (displayToken != null && mHdrListener.mHdrMinPixels > 0) {
                 mHdrListener.register(displayToken);
+                mRegisteredDisplayToken = displayToken;
             }
-            mRegisteredDisplayToken = displayToken;
         }
         recalculateBrightnessCap(data, mAmbientLux, mHdrVisible);
     }
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index d8831fa..03b0cfc 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -78,6 +78,7 @@
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
@@ -148,10 +149,12 @@
             1f, 1f, 1f, 1f
     };
 
+    private final DisplayManagerFlags mDisplayManagerFlags = new DisplayManagerFlags();
+
     @VisibleForTesting
     final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
             new DisplayWhiteBalanceTintController(
-                    LocalServices.getService(DisplayManagerInternal.class));
+                    LocalServices.getService(DisplayManagerInternal.class), mDisplayManagerFlags);
     private final NightDisplayTintController mNightDisplayTintController =
             new NightDisplayTintController();
     private final TintController mGlobalSaturationTintController =
@@ -716,15 +719,16 @@
                         tintController.computeMatrixForCct(to));
                 tintController.setAppliedCct(to);
             } else {
+                final long duration = tintController.getTransitionDurationMilliseconds(to > from);
                 Slog.d(TAG, tintController.getClass().getSimpleName() + " animation started: toCct="
-                        + to + " fromCct=" + from);
+                        + to + " fromCct=" + from + " with duration=" + duration);
                 ValueAnimator valueAnimator = ValueAnimator.ofInt(from, to);
                 tintController.setAnimator(valueAnimator);
                 final CctEvaluator evaluator = tintController.getEvaluator();
                 if (evaluator != null) {
                     valueAnimator.setEvaluator(evaluator);
                 }
-                valueAnimator.setDuration(tintController.getTransitionDurationMilliseconds());
+                valueAnimator.setDuration(duration);
                 valueAnimator.setInterpolator(AnimationUtils.loadInterpolator(
                         getContext(), android.R.interpolator.linear));
                 valueAnimator.addUpdateListener((ValueAnimator animator) -> {
diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
index bf0139f..b9fd1d0 100644
--- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
+++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
@@ -34,6 +34,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.feature.DisplayManagerFlags;
 
 import java.io.PrintWriter;
 
@@ -65,6 +66,8 @@
     boolean mSetUp = false;
     private final float[] mMatrixDisplayWhiteBalance = new float[16];
     private long mTransitionDuration;
+    private long mTransitionDurationIncrease;
+    private long mTransitionDurationDecrease;
     private Boolean mIsAvailable;
     // This feature becomes disallowed if the device is in an unsupported strong/light state.
     private boolean mIsAllowed = true;
@@ -74,8 +77,12 @@
 
     private final DisplayManagerInternal mDisplayManagerInternal;
 
-    DisplayWhiteBalanceTintController(DisplayManagerInternal dm) {
+    private final DisplayManagerFlags mDisplayManagerFlags;
+
+    DisplayWhiteBalanceTintController(DisplayManagerInternal dm,
+            DisplayManagerFlags displayManagerFlags) {
         mDisplayManagerInternal = dm;
+        mDisplayManagerFlags = displayManagerFlags;
     }
 
     @Override
@@ -139,6 +146,16 @@
         mTransitionDuration = res.getInteger(
                 R.integer.config_displayWhiteBalanceTransitionTime);
 
+        if (!mDisplayManagerFlags.isAdaptiveTone2Enabled()) {
+            mTransitionDurationDecrease = mTransitionDuration;
+            mTransitionDurationIncrease = mTransitionDuration;
+        } else {
+            mTransitionDurationIncrease = res.getInteger(
+                    R.integer.config_displayWhiteBalanceTransitionTimeIncrease);
+            mTransitionDurationDecrease = res.getInteger(
+                    R.integer.config_displayWhiteBalanceTransitionTimeDecrease);
+        }
+
         int[] cctRangeMinimums = res.getIntArray(
                 R.array.config_displayWhiteBalanceDisplayRangeMinimums);
         int[] steps = res.getIntArray(R.array.config_displayWhiteBalanceDisplaySteps);
@@ -323,6 +340,11 @@
     }
 
     @Override
+    public long getTransitionDurationMilliseconds(boolean isIncreasing) {
+        return isIncreasing ? mTransitionDurationIncrease : mTransitionDurationDecrease;
+    }
+
+    @Override
     public void dump(PrintWriter pw) {
         synchronized (mLock) {
             pw.println("    mSetUp = " + mSetUp);
@@ -348,6 +370,9 @@
             pw.println("    mMatrixDisplayWhiteBalance = "
                     + matrixToString(mMatrixDisplayWhiteBalance, 4));
             pw.println("    mIsAllowed = " + mIsAllowed);
+            pw.println("    mTransitionDuration = " + mTransitionDuration);
+            pw.println("    mTransitionDurationIncrease = " + mTransitionDurationIncrease);
+            pw.println("    mTransitionDurationDecrease = " + mTransitionDurationDecrease);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java
index 384333a..716661d 100644
--- a/services/core/java/com/android/server/display/color/TintController.java
+++ b/services/core/java/com/android/server/display/color/TintController.java
@@ -75,6 +75,10 @@
         return TRANSITION_DURATION;
     }
 
+    public long getTransitionDurationMilliseconds(boolean direction) {
+        return TRANSITION_DURATION;
+    }
+
     /**
      * Dump debug information.
      */
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index b6273e1..a5e3b708 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -47,25 +47,21 @@
             Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1,
             Flags::enableAdaptiveToneImprovements1);
 
+    private final FlagState mAdaptiveToneImprovements2 = new FlagState(
+            Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_2,
+            Flags::enableAdaptiveToneImprovements2);
+
     private final FlagState mDisplayOffloadFlagState = new FlagState(
             Flags.FLAG_ENABLE_DISPLAY_OFFLOAD,
             Flags::enableDisplayOffload);
 
-    private final FlagState mDisplayResolutionRangeVotingState = new FlagState(
-            Flags.FLAG_ENABLE_DISPLAY_RESOLUTION_RANGE_VOTING,
-            Flags::enableDisplayResolutionRangeVoting);
-
-    private final FlagState mUserPreferredModeVoteState = new FlagState(
-            Flags.FLAG_ENABLE_USER_PREFERRED_MODE_VOTE,
-            Flags::enableUserPreferredModeVote);
-
     private final FlagState mExternalDisplayLimitModeState = new FlagState(
             Flags.FLAG_ENABLE_MODE_LIMIT_FOR_EXTERNAL_DISPLAY,
             Flags::enableModeLimitForExternalDisplay);
 
-    private final FlagState mDisplaysRefreshRatesSynchronizationState = new FlagState(
-            Flags.FLAG_ENABLE_DISPLAYS_REFRESH_RATES_SYNCHRONIZATION,
-            Flags::enableDisplaysRefreshRatesSynchronization);
+    private final FlagState mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState = new FlagState(
+            Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE,
+            Flags::backUpSmoothDisplayAndForcePeakRefreshRate);
 
     /** Returns whether connected display management is enabled or not. */
     public boolean isConnectedDisplayManagementEnabled() {
@@ -88,9 +84,16 @@
         return mAdaptiveToneImprovements1.isEnabled();
     }
 
+    /**
+     * Returns whether adaptive tone improvements are enabled
+     */
+    public boolean isAdaptiveTone2Enabled() {
+        return mAdaptiveToneImprovements2.isEnabled();
+    }
+
     /** Returns whether resolution range voting feature is enabled or not. */
     public boolean isDisplayResolutionRangeVotingEnabled() {
-        return mDisplayResolutionRangeVotingState.isEnabled();
+        return isExternalDisplayLimitModeEnabled();
     }
 
     /**
@@ -98,7 +101,7 @@
      *      {@link com.android.server.display.mode.DisplayModeDirector}
      */
     public boolean isUserPreferredModeVoteEnabled() {
-        return mUserPreferredModeVoteState.isEnabled();
+        return isExternalDisplayLimitModeEnabled();
     }
 
     /**
@@ -112,7 +115,7 @@
      * @return Whether displays refresh rate synchronization is enabled.
      */
     public boolean isDisplaysRefreshRatesSynchronizationEnabled() {
-        return mDisplaysRefreshRatesSynchronizationState.isEnabled();
+        return isExternalDisplayLimitModeEnabled();
     }
 
     /** Returns whether displayoffload is enabled on not */
@@ -120,6 +123,10 @@
         return mDisplayOffloadFlagState.isEnabled();
     }
 
+    public boolean isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled() {
+        return mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState.isEnabled();
+    }
+
     private static class FlagState {
 
         private final String mName;
@@ -133,7 +140,6 @@
             mFlagFunction = flagFunction;
         }
 
-        // TODO(b/297159910): Simplify using READ-ONLY flags when available.
         private boolean isEnabled() {
             if (mEnabledSet) {
                 if (DEBUG) {
@@ -150,19 +156,13 @@
         }
 
         private boolean flagOrSystemProperty(Supplier<Boolean> flagFunction, String flagName) {
+            boolean flagValue = flagFunction.get();
             // TODO(b/299462337) Remove when the infrastructure is ready.
-            if ((Build.IS_ENG || Build.IS_USERDEBUG)
-                    && SystemProperties.getBoolean("persist.sys." + flagName, false)) {
-                return true;
+            if (Build.IS_ENG || Build.IS_USERDEBUG) {
+                return SystemProperties.getBoolean("persist.sys." + flagName + "-override",
+                        flagValue);
             }
-            try {
-                return flagFunction.get();
-            } catch (Throwable ex) {
-                if (DEBUG) {
-                    Slog.i(TAG, "Flags not ready yet. Return false for " + flagName, ex);
-                }
-                return false;
-            }
+            return flagValue;
         }
     }
 }
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 542f26c..3d203fb 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -35,6 +35,14 @@
 }
 
 flag {
+    name: "enable_adaptive_tone_improvements_2"
+    namespace: "display_manager"
+    description: "Feature flag for Further Adaptive Tone Improvements"
+    bug: "294762632"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "enable_display_resolution_range_voting"
     namespace: "display_manager"
     description: "Feature flag to enable voting for ranges of resolutions"
@@ -72,3 +80,11 @@
     bug: "299521647"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "back_up_smooth_display_and_force_peak_refresh_rate"
+    namespace: "display_manager"
+    description: "Feature flag for backing up Smooth Display and Force Peak Refresh Rate"
+    bug: "211737588"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 71ea8cc..ca23844 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -22,6 +22,7 @@
 import static android.view.Display.Mode.INVALID_MODE_ID;
 
 import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE;
+import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay;
 
 import android.annotation.IntegerRes;
 import android.annotation.NonNull;
@@ -176,6 +177,8 @@
 
     private final boolean mIsDisplaysRefreshRatesSynchronizationEnabled;
 
+    private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled;
+
     public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
             @NonNull DisplayManagerFlags displayManagerFlags) {
         this(context, handler, new RealInjector(context), displayManagerFlags);
@@ -191,6 +194,8 @@
             .isExternalDisplayLimitModeEnabled();
         mIsDisplaysRefreshRatesSynchronizationEnabled = displayManagerFlags
             .isDisplaysRefreshRatesSynchronizationEnabled();
+        mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags
+                .isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled();
         mContext = context;
         mHandler = new DisplayModeDirectorHandler(handler.getLooper());
         mInjector = injector;
@@ -1193,8 +1198,7 @@
         public void observe() {
             final ContentResolver cr = mContext.getContentResolver();
             mInjector.registerPeakRefreshRateObserver(cr, this);
-            cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
-                    UserHandle.USER_SYSTEM);
+            mInjector.registerMinRefreshRateObserver(cr, this);
             cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
                     UserHandle.USER_SYSTEM);
             cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/,
@@ -1292,10 +1296,34 @@
 
         private void updateRefreshRateSettingLocked() {
             final ContentResolver cr = mContext.getContentResolver();
+            float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext);
+
             float minRefreshRate = Settings.System.getFloatForUser(cr,
                     Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId());
+            if (Float.isInfinite(minRefreshRate)) {
+                // Infinity means that we want the highest possible refresh rate
+                minRefreshRate = highestRefreshRate;
+
+                if (!mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled) {
+                    // The flag had been turned off, we need to restore the original value
+                    Settings.System.putFloatForUser(cr,
+                            Settings.System.MIN_REFRESH_RATE, minRefreshRate, cr.getUserId());
+                }
+            }
+
             float peakRefreshRate = Settings.System.getFloatForUser(cr,
                     Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate, cr.getUserId());
+            if (Float.isInfinite(peakRefreshRate)) {
+                // Infinity means that we want the highest possible refresh rate
+                peakRefreshRate = highestRefreshRate;
+
+                if (!mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled) {
+                    // The flag had been turned off, we need to restore the original value
+                    Settings.System.putFloatForUser(cr,
+                            Settings.System.PEAK_REFRESH_RATE, peakRefreshRate, cr.getUserId());
+                }
+            }
+
             updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate);
         }
 
@@ -3082,6 +3110,7 @@
 
     interface Injector {
         Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
+        Uri MIN_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE);
 
         @NonNull
         DeviceConfigInterface getDeviceConfig();
@@ -3089,6 +3118,9 @@
         void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
                 @NonNull ContentObserver observer);
 
+        void registerMinRefreshRateObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer);
+
         void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
                 Handler handler);
 
@@ -3140,6 +3172,13 @@
         }
 
         @Override
+        public void registerMinRefreshRateObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer) {
+            cr.registerContentObserver(MIN_REFRESH_RATE_URI, false /*notifyDescendants*/,
+                    observer, UserHandle.USER_SYSTEM);
+        }
+
+        @Override
         public void registerDisplayListener(DisplayManager.DisplayListener listener,
                 Handler handler) {
             getDisplayManager().registerDisplayListener(listener, handler);
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 c6a50ed..7b844a0 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -48,6 +48,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
+import com.android.text.flags.Flags;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -240,21 +241,35 @@
         mContext = context;
         mIsSafeMode = safeMode;
 
-        SystemServerInitThreadPool.submit(() -> {
-            initialize();
+        if (Flags.useOptimizedBoottimeFontLoading()) {
+            Slog.i(TAG, "Using optimized boot-time font loading.");
+            SystemServerInitThreadPool.submit(() -> {
+                initialize();
 
-            // Set system font map only if there is updatable font directory.
-            // If there is no updatable font directory, `initialize` will have already loaded the
-            // system font map, so there's no need to set the system font map again here.
-            if  (mUpdatableFontDir != null) {
-                try {
-                    Typeface.setSystemFontMap(getCurrentFontMap());
-                } catch (IOException | ErrnoException e) {
-                    Slog.w(TAG, "Failed to set system font map of system_server");
+                // Set system font map only if there is updatable font directory.
+                // If there is no updatable font directory, `initialize` will have already loaded
+                // the system font map, so there's no need to set the system font map again here.
+                synchronized (mUpdatableFontDirLock) {
+                    if  (mUpdatableFontDir != null) {
+                        setSystemFontMap();
+                    }
                 }
-            }
+                serviceStarted.complete(null);
+            }, "FontManagerService_create");
+        } else {
+            Slog.i(TAG, "Not using optimized boot-time font loading.");
+            initialize();
+            setSystemFontMap();
             serviceStarted.complete(null);
-        }, "FontManagerService_create");
+        }
+    }
+
+    private void setSystemFontMap() {
+        try {
+            Typeface.setSystemFontMap(getCurrentFontMap());
+        } catch (IOException | ErrnoException e) {
+            Slog.w(TAG, "Failed to set system font map of system_server");
+        }
     }
 
     @Nullable
@@ -291,9 +306,11 @@
         synchronized (mUpdatableFontDirLock) {
             mUpdatableFontDir = createUpdatableFontDir();
             if (mUpdatableFontDir == null) {
-                // If fs-verity is not supported, load preinstalled system font map and use it for
-                // all apps.
-                Typeface.loadPreinstalledSystemFontMap();
+                if (Flags.useOptimizedBoottimeFontLoading()) {
+                    // If fs-verity is not supported, load preinstalled system font map and use it
+                    // for all apps.
+                    Typeface.loadPreinstalledSystemFontMap();
+                }
                 setSerializedFontMap(serializeSystemServerFontMap());
                 return;
             }
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index cd3d2f0..0f40ca0 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -619,8 +619,8 @@
         }
 
         return new FontConfig(
-                config.getFontFamilies(), config.getAliases(), mergedFamilies, mLastModifiedMillis,
-                mConfigVersion);
+                config.getFontFamilies(), config.getAliases(), mergedFamilies,
+                config.getLocaleFallbackCustomizations(), mLastModifiedMillis, mConfigVersion);
     }
 
     private PersistentSystemFontConfig.Config readPersistentConfig() {
diff --git a/services/core/java/com/android/server/input/FocusEventDebugView.java b/services/core/java/com/android/server/input/FocusEventDebugView.java
deleted file mode 100644
index 4b8fabde..0000000
--- a/services/core/java/com/android/server/input/FocusEventDebugView.java
+++ /dev/null
@@ -1,848 +0,0 @@
-/*
- * Copyright 2023 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.input;
-
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
-import static android.util.TypedValue.COMPLEX_UNIT_SP;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import android.animation.LayoutTransition;
-import android.annotation.AnyThread;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.util.DisplayMetrics;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.RoundedCorner;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.WindowInsets;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.HorizontalScrollView;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-
-/**
- *  Displays focus events, such as physical keyboard KeyEvents and non-pointer MotionEvents on
- *  the screen.
- */
-class FocusEventDebugView extends RelativeLayout {
-
-    private static final String TAG = FocusEventDebugView.class.getSimpleName();
-
-    private static final int KEY_FADEOUT_DURATION_MILLIS = 1000;
-    private static final int KEY_TRANSITION_DURATION_MILLIS = 100;
-
-    private static final int OUTER_PADDING_DP = 16;
-    private static final int KEY_SEPARATION_MARGIN_DP = 16;
-    private static final int KEY_VIEW_SIDE_PADDING_DP = 16;
-    private static final int KEY_VIEW_VERTICAL_PADDING_DP = 8;
-    private static final int KEY_VIEW_MIN_WIDTH_DP = 32;
-    private static final int KEY_VIEW_TEXT_SIZE_SP = 12;
-    private static final double ROTATY_GRAPH_HEIGHT_FRACTION = 0.5;
-
-    private final InputManagerService mService;
-    private final int mOuterPadding;
-    private final DisplayMetrics mDm;
-
-    // Tracks all keys that are currently pressed/down.
-    private final Map<Pair<Integer /*deviceId*/, Integer /*scanCode*/>, PressedKeyView>
-            mPressedKeys = new HashMap<>();
-
-    @Nullable
-    private FocusEventDebugGlobalMonitor mFocusEventDebugGlobalMonitor;
-    @Nullable
-    private PressedKeyContainer mPressedKeyContainer;
-    @Nullable
-    private PressedKeyContainer mPressedModifierContainer;
-    private final Supplier<RotaryInputValueView> mRotaryInputValueViewFactory;
-    @Nullable
-    private RotaryInputValueView mRotaryInputValueView;
-    private final Supplier<RotaryInputGraphView> mRotaryInputGraphViewFactory;
-    @Nullable
-    private RotaryInputGraphView mRotaryInputGraphView;
-
-    @VisibleForTesting
-    FocusEventDebugView(Context c, InputManagerService service,
-            Supplier<RotaryInputValueView> rotaryInputValueViewFactory,
-            Supplier<RotaryInputGraphView> rotaryInputGraphViewFactory) {
-        super(c);
-        setFocusableInTouchMode(true);
-
-        mService = service;
-        mRotaryInputValueViewFactory = rotaryInputValueViewFactory;
-        mRotaryInputGraphViewFactory = rotaryInputGraphViewFactory;
-        mDm = mContext.getResources().getDisplayMetrics();
-        mOuterPadding = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, OUTER_PADDING_DP, mDm);
-    }
-
-    FocusEventDebugView(Context c, InputManagerService service) {
-        this(c, service, () -> new RotaryInputValueView(c), () -> new RotaryInputGraphView(c));
-    }
-
-    @Override
-    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        int paddingBottom = 0;
-
-        final RoundedCorner bottomLeft =
-                insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
-        if (bottomLeft != null && !insets.isRound()) {
-            paddingBottom = bottomLeft.getRadius();
-        }
-
-        final RoundedCorner bottomRight =
-                insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
-        if (bottomRight != null && !insets.isRound()) {
-            paddingBottom = Math.max(paddingBottom, bottomRight.getRadius());
-        }
-
-        if (insets.getDisplayCutout() != null) {
-            paddingBottom =
-                    Math.max(paddingBottom, insets.getDisplayCutout().getSafeInsetBottom());
-        }
-
-        setPadding(mOuterPadding, mOuterPadding, mOuterPadding, mOuterPadding + paddingBottom);
-        setClipToPadding(false);
-        invalidate();
-        return super.onApplyWindowInsets(insets);
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        handleKeyEvent(event);
-        return super.dispatchKeyEvent(event);
-    }
-
-    @AnyThread
-    public void updateShowKeyPresses(boolean enabled) {
-        post(() -> handleUpdateShowKeyPresses(enabled));
-    }
-
-    @AnyThread
-    public void updateShowRotaryInput(boolean enabled) {
-        post(() -> handleUpdateShowRotaryInput(enabled));
-    }
-
-    private void handleUpdateShowKeyPresses(boolean enabled) {
-        if (enabled == showKeyPresses()) {
-            return;
-        }
-
-        if (!enabled) {
-            removeView(mPressedKeyContainer);
-            mPressedKeyContainer = null;
-            removeView(mPressedModifierContainer);
-            mPressedModifierContainer = null;
-            return;
-        }
-
-        mPressedKeyContainer = new PressedKeyContainer(mContext);
-        mPressedKeyContainer.setOrientation(LinearLayout.HORIZONTAL);
-        mPressedKeyContainer.setGravity(Gravity.RIGHT | Gravity.BOTTOM);
-        mPressedKeyContainer.setLayoutDirection(LAYOUT_DIRECTION_LTR);
-        final var scroller = new HorizontalScrollView(mContext);
-        scroller.addView(mPressedKeyContainer);
-        scroller.setHorizontalScrollBarEnabled(false);
-        scroller.addOnLayoutChangeListener(
-                (view, l, t, r, b, ol, ot, or, ob) -> scroller.fullScroll(View.FOCUS_RIGHT));
-        scroller.setHorizontalFadingEdgeEnabled(true);
-        LayoutParams scrollerLayoutParams = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
-        scrollerLayoutParams.addRule(ALIGN_PARENT_BOTTOM);
-        scrollerLayoutParams.addRule(ALIGN_PARENT_RIGHT);
-        addView(scroller, scrollerLayoutParams);
-
-        mPressedModifierContainer = new PressedKeyContainer(mContext);
-        mPressedModifierContainer.setOrientation(LinearLayout.VERTICAL);
-        mPressedModifierContainer.setGravity(Gravity.LEFT | Gravity.BOTTOM);
-        LayoutParams modifierLayoutParams = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
-        modifierLayoutParams.addRule(ALIGN_PARENT_BOTTOM);
-        modifierLayoutParams.addRule(ALIGN_PARENT_LEFT);
-        modifierLayoutParams.addRule(LEFT_OF, scroller.getId());
-        addView(mPressedModifierContainer, modifierLayoutParams);
-    }
-
-    @VisibleForTesting
-    void handleUpdateShowRotaryInput(boolean enabled) {
-        if (enabled == showRotaryInput()) {
-            return;
-        }
-
-        if (!enabled) {
-            mFocusEventDebugGlobalMonitor.dispose();
-            mFocusEventDebugGlobalMonitor = null;
-            removeView(mRotaryInputValueView);
-            mRotaryInputValueView = null;
-            removeView(mRotaryInputGraphView);
-            mRotaryInputGraphView = null;
-            return;
-        }
-
-        mFocusEventDebugGlobalMonitor = new FocusEventDebugGlobalMonitor(this, mService);
-
-        mRotaryInputValueView = mRotaryInputValueViewFactory.get();
-        LayoutParams valueLayoutParams = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
-        valueLayoutParams.addRule(CENTER_HORIZONTAL);
-        valueLayoutParams.addRule(ALIGN_PARENT_BOTTOM);
-        addView(mRotaryInputValueView, valueLayoutParams);
-
-        mRotaryInputGraphView = mRotaryInputGraphViewFactory.get();
-        LayoutParams graphLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
-                (int) (ROTATY_GRAPH_HEIGHT_FRACTION * mDm.heightPixels));
-        graphLayoutParams.addRule(CENTER_IN_PARENT);
-        addView(mRotaryInputGraphView, graphLayoutParams);
-    }
-
-    /** Report a key event to the debug view. */
-    @AnyThread
-    public void reportKeyEvent(KeyEvent event) {
-        post(() -> handleKeyEvent(KeyEvent.obtain((KeyEvent) event)));
-    }
-
-    /** Report a motion event to the debug view. */
-    @AnyThread
-    public void reportMotionEvent(MotionEvent event) {
-        if (event.getSource() != InputDevice.SOURCE_ROTARY_ENCODER) {
-            return;
-        }
-
-        post(() -> handleRotaryInput(MotionEvent.obtain((MotionEvent) event)));
-    }
-
-    private void handleKeyEvent(KeyEvent keyEvent) {
-        if (!showKeyPresses()) {
-            return;
-        }
-
-        final var identifier = new Pair<>(keyEvent.getDeviceId(), keyEvent.getScanCode());
-        final var container = KeyEvent.isModifierKey(keyEvent.getKeyCode())
-                ? mPressedModifierContainer
-                : mPressedKeyContainer;
-        PressedKeyView pressedKeyView = mPressedKeys.get(identifier);
-        switch (keyEvent.getAction()) {
-            case KeyEvent.ACTION_DOWN: {
-                if (pressedKeyView != null) {
-                    if (keyEvent.getRepeatCount() == 0) {
-                        Slog.w(TAG, "Got key down for "
-                                + KeyEvent.keyCodeToString(keyEvent.getKeyCode())
-                                + " that was already tracked as being down.");
-                        break;
-                    }
-                    container.handleKeyRepeat(pressedKeyView);
-                    break;
-                }
-
-                pressedKeyView = new PressedKeyView(mContext, getLabel(keyEvent));
-                mPressedKeys.put(identifier, pressedKeyView);
-                container.handleKeyPressed(pressedKeyView);
-                break;
-            }
-            case KeyEvent.ACTION_UP: {
-                if (pressedKeyView == null) {
-                    Slog.w(TAG, "Got key up for " + KeyEvent.keyCodeToString(keyEvent.getKeyCode())
-                            + " that was not tracked as being down.");
-                    break;
-                }
-                mPressedKeys.remove(identifier);
-                container.handleKeyRelease(pressedKeyView);
-                break;
-            }
-            default:
-                break;
-        }
-        keyEvent.recycle();
-    }
-
-    @VisibleForTesting
-    void handleRotaryInput(MotionEvent motionEvent) {
-        if (!showRotaryInput()) {
-            return;
-        }
-
-        float scrollAxisValue = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL);
-        mRotaryInputValueView.updateValue(scrollAxisValue);
-        mRotaryInputGraphView.addValue(scrollAxisValue, motionEvent.getEventTime());
-
-        motionEvent.recycle();
-    }
-
-    private static String getLabel(KeyEvent event) {
-        switch (event.getKeyCode()) {
-            case KeyEvent.KEYCODE_SPACE:
-                return "\u2423";
-            case KeyEvent.KEYCODE_TAB:
-                return "\u21e5";
-            case KeyEvent.KEYCODE_ENTER:
-            case KeyEvent.KEYCODE_NUMPAD_ENTER:
-                return "\u23CE";
-            case KeyEvent.KEYCODE_DEL:
-                return "\u232B";
-            case KeyEvent.KEYCODE_FORWARD_DEL:
-                return "\u2326";
-            case KeyEvent.KEYCODE_ESCAPE:
-                return "ESC";
-            case KeyEvent.KEYCODE_DPAD_UP:
-                return "\u2191";
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-                return "\u2193";
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-                return "\u2190";
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                return "\u2192";
-            case KeyEvent.KEYCODE_DPAD_UP_RIGHT:
-                return "\u2197";
-            case KeyEvent.KEYCODE_DPAD_UP_LEFT:
-                return "\u2196";
-            case KeyEvent.KEYCODE_DPAD_DOWN_RIGHT:
-                return "\u2198";
-            case KeyEvent.KEYCODE_DPAD_DOWN_LEFT:
-                return "\u2199";
-            default:
-                break;
-        }
-
-        final int unicodeChar = event.getUnicodeChar();
-        if (unicodeChar != 0) {
-            return new String(Character.toChars(unicodeChar));
-        }
-
-        final var label = KeyEvent.keyCodeToString(event.getKeyCode());
-        if (label.startsWith("KEYCODE_")) {
-            return label.substring(8);
-        }
-        return label;
-    }
-
-    /** Determine whether to show key presses by checking one of the key-related objects. */
-    private boolean showKeyPresses() {
-        return mPressedKeyContainer != null;
-    }
-
-    /** Determine whether to show rotary input by checking one of the rotary-related objects. */
-    private boolean showRotaryInput() {
-        return mRotaryInputValueView != null;
-    }
-
-    /**
-     * Converts a dimension in scaled pixel units to integer display pixels.
-     */
-    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) {
-        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm);
-    }
-
-    private static class PressedKeyView extends TextView {
-
-        private static final ColorFilter sInvertColors = new ColorMatrixColorFilter(new float[]{
-                -1.0f,     0,     0,    0, 255, // red
-                0, -1.0f,     0,    0, 255, // green
-                0,     0, -1.0f,    0, 255, // blue
-                0,     0,     0, 1.0f, 0    // alpha
-        });
-
-        PressedKeyView(Context c, String label) {
-            super(c);
-
-            final var dm = c.getResources().getDisplayMetrics();
-            final int keyViewSidePadding =
-                    (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, KEY_VIEW_SIDE_PADDING_DP, dm);
-            final int keyViewVerticalPadding =
-                    (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, KEY_VIEW_VERTICAL_PADDING_DP,
-                            dm);
-            final int keyViewMinWidth =
-                    (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, KEY_VIEW_MIN_WIDTH_DP, dm);
-            final int textSize =
-                    (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, KEY_VIEW_TEXT_SIZE_SP, dm);
-
-            setText(label);
-            setGravity(Gravity.CENTER);
-            setMinimumWidth(keyViewMinWidth);
-            setTextSize(textSize);
-            setTypeface(Typeface.SANS_SERIF);
-            setBackgroundResource(R.drawable.focus_event_pressed_key_background);
-            setPaddingRelative(keyViewSidePadding, keyViewVerticalPadding, keyViewSidePadding,
-                    keyViewVerticalPadding);
-
-            setHighlighted(true);
-        }
-
-        void setHighlighted(boolean isHighlighted) {
-            if (isHighlighted) {
-                setTextColor(Color.BLACK);
-                getBackground().setColorFilter(sInvertColors);
-            } else {
-                setTextColor(Color.WHITE);
-                getBackground().clearColorFilter();
-            }
-            invalidate();
-        }
-    }
-
-    private static class PressedKeyContainer extends LinearLayout {
-
-        private final MarginLayoutParams mPressedKeyLayoutParams;
-
-        PressedKeyContainer(Context c) {
-            super(c);
-
-            final var dm = c.getResources().getDisplayMetrics();
-            final int keySeparationMargin =
-                    (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, KEY_SEPARATION_MARGIN_DP, dm);
-
-            final var transition = new LayoutTransition();
-            transition.disableTransitionType(LayoutTransition.APPEARING);
-            transition.disableTransitionType(LayoutTransition.DISAPPEARING);
-            transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-            transition.setDuration(KEY_TRANSITION_DURATION_MILLIS);
-            setLayoutTransition(transition);
-
-            mPressedKeyLayoutParams = new MarginLayoutParams(WRAP_CONTENT, WRAP_CONTENT);
-            if (getOrientation() == VERTICAL) {
-                mPressedKeyLayoutParams.setMargins(0, keySeparationMargin, 0, 0);
-            } else {
-                mPressedKeyLayoutParams.setMargins(keySeparationMargin, 0, 0, 0);
-            }
-        }
-
-        public void handleKeyPressed(PressedKeyView pressedKeyView) {
-            addView(pressedKeyView, getChildCount(), mPressedKeyLayoutParams);
-            invalidate();
-        }
-
-        public void handleKeyRepeat(PressedKeyView repeatedKeyView) {
-            // Do nothing for now.
-        }
-
-        public void handleKeyRelease(PressedKeyView releasedKeyView) {
-            releasedKeyView.setHighlighted(false);
-            releasedKeyView.clearAnimation();
-            releasedKeyView.animate()
-                    .alpha(0)
-                    .setDuration(KEY_FADEOUT_DURATION_MILLIS)
-                    .setInterpolator(new AccelerateInterpolator())
-                    .withEndAction(this::cleanUpPressedKeyViews)
-                    .start();
-        }
-
-        private void cleanUpPressedKeyViews() {
-            int numChildrenToRemove = 0;
-            for (int i = 0; i < getChildCount(); i++) {
-                final View child = getChildAt(i);
-                if (child.getAlpha() != 0) {
-                    break;
-                }
-                child.setVisibility(View.GONE);
-                child.clearAnimation();
-                numChildrenToRemove++;
-            }
-            removeViews(0, numChildrenToRemove);
-            invalidate();
-        }
-    }
-
-    // TODO(b/286086154): move RotaryInputGraphView and RotaryInputValueView to a subpackage.
-
-    /** Draws the most recent rotary input value and indicates whether the source is active. */
-    @VisibleForTesting
-    static class RotaryInputValueView extends TextView {
-
-        private static final int INACTIVE_TEXT_COLOR = 0xffff00ff;
-        private static final int ACTIVE_TEXT_COLOR = 0xff420f28;
-        private static final int TEXT_SIZE_SP = 8;
-        private static final int SIDE_PADDING_SP = 4;
-        /** Determines how long the active status lasts. */
-        private static final int ACTIVE_STATUS_DURATION = 250 /* milliseconds */;
-        private static final ColorFilter ACTIVE_BACKGROUND_FILTER =
-                new ColorMatrixColorFilter(new float[]{
-                        0, 0, 0, 0, 255, // red
-                        0, 0, 0, 0,   0, // green
-                        0, 0, 0, 0, 255, // blue
-                        0, 0, 0, 0, 200  // alpha
-                });
-
-        private final Runnable mUpdateActivityStatusCallback = () -> updateActivityStatus(false);
-        private final float mScaledVerticalScrollFactor;
-
-        @VisibleForTesting
-        RotaryInputValueView(Context c) {
-            super(c);
-
-            DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
-            mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor();
-
-            setText(getFormattedValue(0));
-            setTextColor(INACTIVE_TEXT_COLOR);
-            setTextSize(applyDimensionSp(TEXT_SIZE_SP, dm));
-            setPaddingRelative(applyDimensionSp(SIDE_PADDING_SP, dm), 0,
-                    applyDimensionSp(SIDE_PADDING_SP, dm), 0);
-            setTypeface(null, Typeface.BOLD);
-            setBackgroundResource(R.drawable.focus_event_rotary_input_background);
-        }
-
-        void updateValue(float value) {
-            removeCallbacks(mUpdateActivityStatusCallback);
-
-            setText(getFormattedValue(value * mScaledVerticalScrollFactor));
-
-            updateActivityStatus(true);
-            postDelayed(mUpdateActivityStatusCallback, ACTIVE_STATUS_DURATION);
-        }
-
-        @VisibleForTesting
-        void updateActivityStatus(boolean active) {
-            if (active) {
-                setTextColor(ACTIVE_TEXT_COLOR);
-                getBackground().setColorFilter(ACTIVE_BACKGROUND_FILTER);
-            } else {
-                setTextColor(INACTIVE_TEXT_COLOR);
-                getBackground().clearColorFilter();
-            }
-        }
-
-        private static String getFormattedValue(float value) {
-            return String.format("%s%.1f", value < 0 ? "-" : "+", Math.abs(value));
-        }
-    }
-
-    /**
-     * Shows a graph with the rotary input values as a function of time.
-     * The graph gets reset if no action is received for a certain amount of time.
-     */
-    @VisibleForTesting
-    static class RotaryInputGraphView extends View {
-
-        private static final int FRAME_COLOR = 0xbf741b47;
-        private static final int FRAME_WIDTH_SP = 2;
-        private static final int FRAME_BORDER_GAP_SP = 10;
-        private static final int FRAME_TEXT_SIZE_SP = 10;
-        private static final int FRAME_TEXT_OFFSET_SP = 2;
-        private static final int GRAPH_COLOR = 0xffff00ff;
-        private static final int GRAPH_LINE_WIDTH_SP = 1;
-        private static final int GRAPH_POINT_RADIUS_SP = 4;
-        private static final long MAX_SHOWN_TIME_INTERVAL = TimeUnit.SECONDS.toMillis(5);
-        private static final float DEFAULT_FRAME_CENTER_POSITION = 0;
-        private static final int MAX_GRAPH_VALUES_SIZE = 400;
-        /** Maximum time between values so that they are considered part of the same gesture. */
-        private static final long MAX_GESTURE_TIME = TimeUnit.SECONDS.toMillis(1);
-
-        private final DisplayMetrics mDm;
-        /**
-         * Distance in position units (amount scrolled in display pixels) from the center to the
-         * top/bottom frame lines.
-         */
-        private final float mFrameCenterToBorderDistance;
-        private final float mScaledVerticalScrollFactor;
-        private final Locale mDefaultLocale;
-        private final Paint mFramePaint = new Paint();
-        private final Paint mFrameTextPaint = new Paint();
-        private final Paint mGraphLinePaint = new Paint();
-        private final Paint mGraphPointPaint = new Paint();
-
-        private final CyclicBuffer mGraphValues = new CyclicBuffer(MAX_GRAPH_VALUES_SIZE);
-        /** Position at which graph values are placed at the center of the graph. */
-        private float mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION;
-
-        @VisibleForTesting
-        RotaryInputGraphView(Context c) {
-            super(c);
-
-            mDm = mContext.getResources().getDisplayMetrics();
-            // This makes the center-to-border distance equivalent to the display height, meaning
-            // that the total height of the graph is equivalent to 2x the display height.
-            mFrameCenterToBorderDistance = mDm.heightPixels;
-            mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor();
-            mDefaultLocale = Locale.getDefault();
-
-            mFramePaint.setColor(FRAME_COLOR);
-            mFramePaint.setStrokeWidth(applyDimensionSp(FRAME_WIDTH_SP, mDm));
-
-            mFrameTextPaint.setColor(GRAPH_COLOR);
-            mFrameTextPaint.setTextSize(applyDimensionSp(FRAME_TEXT_SIZE_SP, mDm));
-
-            mGraphLinePaint.setColor(GRAPH_COLOR);
-            mGraphLinePaint.setStrokeWidth(applyDimensionSp(GRAPH_LINE_WIDTH_SP, mDm));
-            mGraphLinePaint.setStrokeCap(Paint.Cap.ROUND);
-            mGraphLinePaint.setStrokeJoin(Paint.Join.ROUND);
-
-            mGraphPointPaint.setColor(GRAPH_COLOR);
-            mGraphPointPaint.setStrokeWidth(applyDimensionSp(GRAPH_POINT_RADIUS_SP, mDm));
-            mGraphPointPaint.setStrokeCap(Paint.Cap.ROUND);
-            mGraphPointPaint.setStrokeJoin(Paint.Join.ROUND);
-        }
-
-        /**
-         * Reads new scroll axis value and updates the list accordingly. Old positions are
-         * kept at the front (what you would get with getFirst), while the recent positions are
-         * kept at the back (what you would get with getLast). Also updates the frame center
-         * position to handle out-of-bounds cases.
-         */
-        void addValue(float scrollAxisValue, long eventTime) {
-            // Remove values that are too old.
-            while (mGraphValues.getSize() > 0
-                    && (eventTime - mGraphValues.getFirst().mTime) > MAX_SHOWN_TIME_INTERVAL) {
-                mGraphValues.removeFirst();
-            }
-
-            // If there are no recent values, reset the frame center.
-            if (mGraphValues.getSize() == 0) {
-                mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION;
-            }
-
-            // Handle new value. We multiply the scroll axis value by the scaled scroll factor to
-            // get the amount of pixels to be scrolled. We also compute the accumulated position
-            // by adding the current value to the last one (if not empty).
-            final float displacement = scrollAxisValue * mScaledVerticalScrollFactor;
-            final float prevPos = (mGraphValues.getSize() == 0 ? 0 : mGraphValues.getLast().mPos);
-            final float pos = prevPos + displacement;
-
-            mGraphValues.add(pos, eventTime);
-
-            // The difference between the distance of the most recent position from the center
-            // frame (pos - mFrameCenterPosition) and the maximum allowed distance from the center
-            // frame (mFrameCenterToBorderDistance).
-            final float verticalDiff = Math.abs(pos - mFrameCenterPosition)
-                    - mFrameCenterToBorderDistance;
-            // If needed, translate frame.
-            if (verticalDiff > 0) {
-                final int sign = pos - mFrameCenterPosition < 0 ? -1 : 1;
-                // Here, we update the center frame position by the exact amount needed for us to
-                // stay within the maximum allowed distance from the center frame.
-                mFrameCenterPosition += sign * verticalDiff;
-            }
-
-            // Redraw canvas.
-            invalidate();
-        }
-
-        @Override
-        protected void onDraw(Canvas canvas) {
-            super.onDraw(canvas);
-
-            // Note: vertical coordinates in Canvas go from top to bottom,
-            // that is bottomY > middleY > topY.
-            final int verticalMargin = applyDimensionSp(FRAME_BORDER_GAP_SP, mDm);
-            final int topY = verticalMargin;
-            final int bottomY = getHeight() - verticalMargin;
-            final int middleY = (topY + bottomY) / 2;
-
-            // Note: horizontal coordinates in Canvas go from left to right,
-            // that is rightX > leftX.
-            final int leftX = 0;
-            final int rightX = getWidth();
-
-            // Draw the frame, which includes 3 lines that show the maximum,
-            // minimum and middle positions of the graph.
-            canvas.drawLine(leftX, topY, rightX, topY, mFramePaint);
-            canvas.drawLine(leftX, middleY, rightX, middleY, mFramePaint);
-            canvas.drawLine(leftX, bottomY, rightX, bottomY, mFramePaint);
-
-            // Draw the position that each frame line corresponds to.
-            final int frameTextOffset = applyDimensionSp(FRAME_TEXT_OFFSET_SP, mDm);
-            canvas.drawText(
-                    String.format(mDefaultLocale, "%.1f",
-                            mFrameCenterPosition + mFrameCenterToBorderDistance),
-                    leftX,
-                    topY - frameTextOffset, mFrameTextPaint
-            );
-            canvas.drawText(
-                    String.format(mDefaultLocale, "%.1f", mFrameCenterPosition),
-                    leftX,
-                    middleY - frameTextOffset, mFrameTextPaint
-            );
-            canvas.drawText(
-                    String.format(mDefaultLocale, "%.1f",
-                            mFrameCenterPosition - mFrameCenterToBorderDistance),
-                    leftX,
-                    bottomY - frameTextOffset, mFrameTextPaint
-            );
-
-            // If there are no graph values to be drawn, stop here.
-            if (mGraphValues.getSize() == 0) {
-                return;
-            }
-
-            // Draw the graph using the times and positions.
-            // We start at the most recent value (which should be drawn at the right) and move
-            // to the older values (which should be drawn to the left of more recent ones). Negative
-            // indices are handled by circuling back to the end of the buffer.
-            final long mostRecentTime = mGraphValues.getLast().mTime;
-            float prevCoordX = 0;
-            float prevCoordY = 0;
-            float prevAge = 0;
-            for (Iterator<GraphValue> iter = mGraphValues.reverseIterator(); iter.hasNext();) {
-                final GraphValue value = iter.next();
-
-                final int age = (int) (mostRecentTime - value.mTime);
-                final float pos = value.mPos;
-
-                // We get the horizontal coordinate in time units from left to right with
-                // (MAX_SHOWN_TIME_INTERVAL - age). Then, we rescale it to match the canvas
-                // units by dividing it by the time-domain length (MAX_SHOWN_TIME_INTERVAL)
-                // and by multiplying it by the canvas length (rightX - leftX). Finally, we
-                // offset the coordinate by adding it to leftX.
-                final float coordX = leftX + ((float) (MAX_SHOWN_TIME_INTERVAL - age)
-                        / MAX_SHOWN_TIME_INTERVAL) * (rightX - leftX);
-
-                // We get the vertical coordinate in position units from middle to top with
-                // (pos - mFrameCenterPosition). Then, we rescale it to match the canvas
-                // units by dividing it by half of the position-domain length
-                // (mFrameCenterToBorderDistance) and by multiplying it by half of the canvas
-                // length (middleY - topY). Finally, we offset the coordinate by subtracting
-                // it from middleY (we can't "add" here because the coordinate grows from top
-                // to bottom).
-                final float coordY = middleY - ((pos - mFrameCenterPosition)
-                        / mFrameCenterToBorderDistance) * (middleY - topY);
-
-                // Draw a point for this value.
-                canvas.drawPoint(coordX, coordY, mGraphPointPaint);
-
-                // If this value is part of the same gesture as the previous one, draw a line
-                // between them. We ignore the first value (with age = 0).
-                if (age != 0 && (age - prevAge) <= MAX_GESTURE_TIME) {
-                    canvas.drawLine(prevCoordX, prevCoordY, coordX, coordY, mGraphLinePaint);
-                }
-
-                prevCoordX = coordX;
-                prevCoordY = coordY;
-                prevAge = age;
-            }
-        }
-
-        @VisibleForTesting
-        float getFrameCenterPosition() {
-            return mFrameCenterPosition;
-        }
-
-        /**
-         * Holds data needed to draw each entry in the graph.
-         */
-        private static class GraphValue {
-            /** Position. */
-            float mPos;
-            /** Time when this value was added. */
-            long mTime;
-
-            GraphValue(float pos, long time) {
-                this.mPos = pos;
-                this.mTime = time;
-            }
-        }
-
-        /**
-         * Holds the graph values as a cyclic buffer. It has a fixed capacity, and it replaces the
-         * old values with new ones to avoid creating new objects.
-         */
-        private static class CyclicBuffer {
-            private final GraphValue[] mValues;
-            private final int mCapacity;
-            private int mSize = 0;
-            private int mLastIndex = 0;
-
-            // The iteration index and counter are here to make it easier to reset them.
-            /** Determines the value currently pointed by the iterator. */
-            private int mIteratorIndex;
-            /** Counts how many values have been iterated through. */
-            private int mIteratorCount;
-
-            /** Used traverse the values in reverse order. */
-            private final Iterator<GraphValue> mReverseIterator = new Iterator<GraphValue>() {
-                @Override
-                public boolean hasNext() {
-                    return mIteratorCount <= mSize;
-                }
-
-                @Override
-                public GraphValue next() {
-                    // Returns the value currently pointed by the iterator and moves the iterator to
-                    // the previous one.
-                    mIteratorCount++;
-                    return mValues[(mIteratorIndex-- + mCapacity) % mCapacity];
-                }
-            };
-
-            CyclicBuffer(int capacity) {
-                mCapacity = capacity;
-                mValues = new GraphValue[capacity];
-            }
-
-            /**
-             * Add new graph value. If there is an existing object, we replace its data with the
-             * new one. With this, we re-use old objects instead of creating new ones.
-             */
-            void add(float pos, long time) {
-                mLastIndex = (mLastIndex + 1) % mCapacity;
-                if (mValues[mLastIndex] == null) {
-                    mValues[mLastIndex] = new GraphValue(pos, time);
-                } else {
-                    final GraphValue oldValue = mValues[mLastIndex];
-                    oldValue.mPos = pos;
-                    oldValue.mTime = time;
-                }
-
-                // If needed, account for new value in the buffer size.
-                if (mSize != mCapacity) {
-                    mSize++;
-                }
-            }
-
-            int getSize() {
-                return mSize;
-            }
-
-            GraphValue getFirst() {
-                final int distanceBetweenLastAndFirst = (mCapacity - mSize) + 1;
-                final int firstIndex = (mLastIndex + distanceBetweenLastAndFirst) % mCapacity;
-                return mValues[firstIndex];
-            }
-
-            GraphValue getLast() {
-                return mValues[mLastIndex];
-            }
-
-            void removeFirst() {
-                mSize--;
-            }
-
-            /** Returns an iterator pointing at the last value. */
-            Iterator<GraphValue> reverseIterator() {
-                mIteratorIndex = mLastIndex;
-                mIteratorCount = 1;
-                return mReverseIterator;
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
index 2ede56d..a2c8748 100644
--- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -62,10 +62,10 @@
         mWindowHandle.ownerUid = uid;
         mWindowHandle.scaleFactor = 1.0f;
         mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
-        mWindowHandle.inputConfig =
-                InputConfig.NOT_FOCUSABLE | InputConfig.SPY | InputConfig.TRUSTED_OVERLAY;
+        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SPY;
 
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_GESTURE_MONITOR);
         t.setPosition(mInputSurface, 0, 0);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 6b399de..2533e02 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -117,6 +117,7 @@
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import com.android.server.input.InputManagerInternal.LidSwitchCallback;
+import com.android.server.input.debug.FocusEventDebugView;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.policy.WindowManagerPolicy;
 
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 0eb620f..8580b96 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -71,6 +71,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.internal.notification.SystemNotificationChannels;
@@ -99,7 +100,7 @@
  *
  * @hide
  */
-final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
+class KeyboardLayoutManager implements InputManager.InputDeviceListener {
 
     private static final String TAG = "KeyboardLayoutManager";
 
@@ -1245,11 +1246,17 @@
                         isFirstConfiguration);
         for (int i = 0; i < imeInfoList.size(); i++) {
             KeyboardLayoutInfo layoutInfo = layoutInfoList.get(i);
-            boolean noLayoutFound = layoutInfo == null || layoutInfo.mDescriptor == null;
-            configurationEventBuilder.addLayoutSelection(imeInfoList.get(i).mImeSubtype,
-                    noLayoutFound ? null : getKeyboardLayout(layoutInfo.mDescriptor),
-                    noLayoutFound ? LAYOUT_SELECTION_CRITERIA_DEFAULT
-                            : layoutInfo.mSelectionCriteria);
+            String layoutName = null;
+            int layoutSelectionCriteria = LAYOUT_SELECTION_CRITERIA_DEFAULT;
+            if (layoutInfo != null && layoutInfo.mDescriptor != null) {
+                layoutSelectionCriteria = layoutInfo.mSelectionCriteria;
+                KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(layoutInfo.mDescriptor);
+                if (d != null) {
+                    layoutName = d.keyboardLayoutName;
+                }
+            }
+            configurationEventBuilder.addLayoutSelection(imeInfoList.get(i).mImeSubtype, layoutName,
+                    layoutSelectionCriteria);
         }
         KeyboardMetricsCollector.logKeyboardConfiguredAtom(configurationEventBuilder.build());
     }
@@ -1295,7 +1302,8 @@
     }
 
     @SuppressLint("MissingPermission")
-    private List<ImeInfo> getImeInfoListForLayoutMapping() {
+    @VisibleForTesting
+    public List<ImeInfo> getImeInfoListForLayoutMapping() {
         List<ImeInfo> imeInfoList = new ArrayList<>();
         UserManager userManager = Objects.requireNonNull(
                 mContext.getSystemService(UserManager.class));
@@ -1402,7 +1410,8 @@
         }
     }
 
-    private static class ImeInfo {
+    @VisibleForTesting
+    public static class ImeInfo {
         @UserIdInt int mUserId;
         @NonNull InputMethodSubtypeHandle mImeSubtypeHandle;
         @Nullable InputMethodSubtype mImeSubtype;
diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
index 08e5977..2dd2a16 100644
--- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
+++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
@@ -491,7 +491,7 @@
             private final InputDevice mInputDevice;
             private boolean mIsFirstConfiguration;
             private final List<InputMethodSubtype> mImeSubtypeList = new ArrayList<>();
-            private final List<KeyboardLayout> mSelectedLayoutList = new ArrayList<>();
+            private final List<String> mSelectedLayoutList = new ArrayList<>();
             private final List<Integer> mLayoutSelectionCriteriaList = new ArrayList<>();
 
             public Builder(@NonNull InputDevice inputDevice) {
@@ -511,7 +511,7 @@
              * Adds keyboard layout configuration info for a particular IME subtype language
              */
             public Builder addLayoutSelection(@NonNull InputMethodSubtype imeSubtype,
-                    @Nullable KeyboardLayout selectedLayout,
+                    @Nullable String selectedLayout,
                     @LayoutSelectionCriteria int layoutSelectionCriteria) {
                 Objects.requireNonNull(imeSubtype, "IME subtype provided should not be null");
                 if (!isValidSelectionCriteria(layoutSelectionCriteria)) {
@@ -533,7 +533,6 @@
                 }
                 List<LayoutConfiguration> configurationList = new ArrayList<>();
                 for (int i = 0; i < size; i++) {
-                    KeyboardLayout selectedLayout = mSelectedLayoutList.get(i);
                     @LayoutSelectionCriteria int layoutSelectionCriteria =
                             mLayoutSelectionCriteriaList.get(i);
                     InputMethodSubtype imeSubtype = mImeSubtypeList.get(i);
@@ -552,9 +551,9 @@
                             imeSubtype.getPhysicalKeyboardHintLayoutType());
 
                     // Sanitize null values
-                    String keyboardLayoutName =
-                            selectedLayout == null ? DEFAULT_LAYOUT_NAME
-                                    : selectedLayout.getLabel();
+                    String keyboardLayoutName = mSelectedLayoutList.get(i) == null
+                            ? DEFAULT_LAYOUT_NAME
+                            : mSelectedLayoutList.get(i);
 
                     configurationList.add(
                             new LayoutConfiguration(keyboardLayoutType, keyboardLanguageTag,
diff --git a/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java b/services/core/java/com/android/server/input/debug/FocusEventDebugGlobalMonitor.java
similarity index 94%
rename from services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java
rename to services/core/java/com/android/server/input/debug/FocusEventDebugGlobalMonitor.java
index 67c221f..2b21e49 100644
--- a/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java
+++ b/services/core/java/com/android/server/input/debug/FocusEventDebugGlobalMonitor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.input;
+package com.android.server.input.debug;
 
 import android.view.Display;
 import android.view.InputEvent;
@@ -22,6 +22,7 @@
 import android.view.MotionEvent;
 
 import com.android.server.UiThread;
+import com.android.server.input.InputManagerService;
 
 /**
  * Receives input events before they are dispatched and reports them to FocusEventDebugView.
diff --git a/services/core/java/com/android/server/input/debug/FocusEventDebugView.java b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
new file mode 100644
index 0000000..6eec0de
--- /dev/null
+++ b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
@@ -0,0 +1,466 @@
+/*
+ * Copyright 2023 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.input.debug;
+
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import static android.util.TypedValue.COMPLEX_UNIT_SP;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.animation.LayoutTransition;
+import android.annotation.AnyThread;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Typeface;
+import android.util.DisplayMetrics;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.RoundedCorner;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.input.InputManagerService;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
+/**
+ *  Displays focus events, such as physical keyboard KeyEvents and non-pointer MotionEvents on
+ *  the screen.
+ */
+public class FocusEventDebugView extends RelativeLayout {
+
+    private static final String TAG = FocusEventDebugView.class.getSimpleName();
+
+    private static final int KEY_FADEOUT_DURATION_MILLIS = 1000;
+    private static final int KEY_TRANSITION_DURATION_MILLIS = 100;
+
+    private static final int OUTER_PADDING_DP = 16;
+    private static final int KEY_SEPARATION_MARGIN_DP = 16;
+    private static final int KEY_VIEW_SIDE_PADDING_DP = 16;
+    private static final int KEY_VIEW_VERTICAL_PADDING_DP = 8;
+    private static final int KEY_VIEW_MIN_WIDTH_DP = 32;
+    private static final int KEY_VIEW_TEXT_SIZE_SP = 12;
+    private static final double ROTATY_GRAPH_HEIGHT_FRACTION = 0.5;
+
+    private final InputManagerService mService;
+    private final int mOuterPadding;
+    private final DisplayMetrics mDm;
+
+    // Tracks all keys that are currently pressed/down.
+    private final Map<Pair<Integer /*deviceId*/, Integer /*scanCode*/>, PressedKeyView>
+            mPressedKeys = new HashMap<>();
+
+    @Nullable
+    private FocusEventDebugGlobalMonitor mFocusEventDebugGlobalMonitor;
+    @Nullable
+    private PressedKeyContainer mPressedKeyContainer;
+    @Nullable
+    private PressedKeyContainer mPressedModifierContainer;
+    private final Supplier<RotaryInputValueView> mRotaryInputValueViewFactory;
+    @Nullable
+    private RotaryInputValueView mRotaryInputValueView;
+    private final Supplier<RotaryInputGraphView> mRotaryInputGraphViewFactory;
+    @Nullable
+    private RotaryInputGraphView mRotaryInputGraphView;
+
+    @VisibleForTesting
+    FocusEventDebugView(Context c, InputManagerService service,
+            Supplier<RotaryInputValueView> rotaryInputValueViewFactory,
+            Supplier<RotaryInputGraphView> rotaryInputGraphViewFactory) {
+        super(c);
+        setFocusableInTouchMode(true);
+
+        mService = service;
+        mRotaryInputValueViewFactory = rotaryInputValueViewFactory;
+        mRotaryInputGraphViewFactory = rotaryInputGraphViewFactory;
+        mDm = mContext.getResources().getDisplayMetrics();
+        mOuterPadding = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, OUTER_PADDING_DP, mDm);
+    }
+
+    public FocusEventDebugView(Context c, InputManagerService service) {
+        this(c, service, () -> new RotaryInputValueView(c), () -> new RotaryInputGraphView(c));
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        int paddingBottom = 0;
+
+        final RoundedCorner bottomLeft =
+                insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
+        if (bottomLeft != null && !insets.isRound()) {
+            paddingBottom = bottomLeft.getRadius();
+        }
+
+        final RoundedCorner bottomRight =
+                insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
+        if (bottomRight != null && !insets.isRound()) {
+            paddingBottom = Math.max(paddingBottom, bottomRight.getRadius());
+        }
+
+        if (insets.getDisplayCutout() != null) {
+            paddingBottom =
+                    Math.max(paddingBottom, insets.getDisplayCutout().getSafeInsetBottom());
+        }
+
+        setPadding(mOuterPadding, mOuterPadding, mOuterPadding, mOuterPadding + paddingBottom);
+        setClipToPadding(false);
+        invalidate();
+        return super.onApplyWindowInsets(insets);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        handleKeyEvent(event);
+        return super.dispatchKeyEvent(event);
+    }
+
+    /** Determines whether to show the key presses visualization. */
+    @AnyThread
+    public void updateShowKeyPresses(boolean enabled) {
+        post(() -> handleUpdateShowKeyPresses(enabled));
+    }
+
+    /** Determines whether to show the rotary input visualization. */
+    @AnyThread
+    public void updateShowRotaryInput(boolean enabled) {
+        post(() -> handleUpdateShowRotaryInput(enabled));
+    }
+
+    private void handleUpdateShowKeyPresses(boolean enabled) {
+        if (enabled == showKeyPresses()) {
+            return;
+        }
+
+        if (!enabled) {
+            removeView(mPressedKeyContainer);
+            mPressedKeyContainer = null;
+            removeView(mPressedModifierContainer);
+            mPressedModifierContainer = null;
+            return;
+        }
+
+        mPressedKeyContainer = new PressedKeyContainer(mContext);
+        mPressedKeyContainer.setOrientation(LinearLayout.HORIZONTAL);
+        mPressedKeyContainer.setGravity(Gravity.RIGHT | Gravity.BOTTOM);
+        mPressedKeyContainer.setLayoutDirection(LAYOUT_DIRECTION_LTR);
+        final var scroller = new HorizontalScrollView(mContext);
+        scroller.addView(mPressedKeyContainer);
+        scroller.setHorizontalScrollBarEnabled(false);
+        scroller.addOnLayoutChangeListener(
+                (view, l, t, r, b, ol, ot, or, ob) -> scroller.fullScroll(View.FOCUS_RIGHT));
+        scroller.setHorizontalFadingEdgeEnabled(true);
+        LayoutParams scrollerLayoutParams = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
+        scrollerLayoutParams.addRule(ALIGN_PARENT_BOTTOM);
+        scrollerLayoutParams.addRule(ALIGN_PARENT_RIGHT);
+        addView(scroller, scrollerLayoutParams);
+
+        mPressedModifierContainer = new PressedKeyContainer(mContext);
+        mPressedModifierContainer.setOrientation(LinearLayout.VERTICAL);
+        mPressedModifierContainer.setGravity(Gravity.LEFT | Gravity.BOTTOM);
+        LayoutParams modifierLayoutParams = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
+        modifierLayoutParams.addRule(ALIGN_PARENT_BOTTOM);
+        modifierLayoutParams.addRule(ALIGN_PARENT_LEFT);
+        modifierLayoutParams.addRule(LEFT_OF, scroller.getId());
+        addView(mPressedModifierContainer, modifierLayoutParams);
+    }
+
+    @VisibleForTesting
+    void handleUpdateShowRotaryInput(boolean enabled) {
+        if (enabled == showRotaryInput()) {
+            return;
+        }
+
+        if (!enabled) {
+            mFocusEventDebugGlobalMonitor.dispose();
+            mFocusEventDebugGlobalMonitor = null;
+            removeView(mRotaryInputValueView);
+            mRotaryInputValueView = null;
+            removeView(mRotaryInputGraphView);
+            mRotaryInputGraphView = null;
+            return;
+        }
+
+        mFocusEventDebugGlobalMonitor = new FocusEventDebugGlobalMonitor(this, mService);
+
+        mRotaryInputValueView = mRotaryInputValueViewFactory.get();
+        LayoutParams valueLayoutParams = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
+        valueLayoutParams.addRule(CENTER_HORIZONTAL);
+        valueLayoutParams.addRule(ALIGN_PARENT_BOTTOM);
+        addView(mRotaryInputValueView, valueLayoutParams);
+
+        mRotaryInputGraphView = mRotaryInputGraphViewFactory.get();
+        LayoutParams graphLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
+                (int) (ROTATY_GRAPH_HEIGHT_FRACTION * mDm.heightPixels));
+        graphLayoutParams.addRule(CENTER_IN_PARENT);
+        addView(mRotaryInputGraphView, graphLayoutParams);
+    }
+
+    /** Report a key event to the debug view. */
+    @AnyThread
+    public void reportKeyEvent(KeyEvent event) {
+        post(() -> handleKeyEvent(KeyEvent.obtain((KeyEvent) event)));
+    }
+
+    /** Report a motion event to the debug view. */
+    @AnyThread
+    public void reportMotionEvent(MotionEvent event) {
+        if (event.getSource() != InputDevice.SOURCE_ROTARY_ENCODER) {
+            return;
+        }
+
+        post(() -> handleRotaryInput(MotionEvent.obtain((MotionEvent) event)));
+    }
+
+    private void handleKeyEvent(KeyEvent keyEvent) {
+        if (!showKeyPresses()) {
+            return;
+        }
+
+        final var identifier = new Pair<>(keyEvent.getDeviceId(), keyEvent.getScanCode());
+        final var container = KeyEvent.isModifierKey(keyEvent.getKeyCode())
+                ? mPressedModifierContainer
+                : mPressedKeyContainer;
+        PressedKeyView pressedKeyView = mPressedKeys.get(identifier);
+        switch (keyEvent.getAction()) {
+            case KeyEvent.ACTION_DOWN: {
+                if (pressedKeyView != null) {
+                    if (keyEvent.getRepeatCount() == 0) {
+                        Slog.w(TAG, "Got key down for "
+                                + KeyEvent.keyCodeToString(keyEvent.getKeyCode())
+                                + " that was already tracked as being down.");
+                        break;
+                    }
+                    container.handleKeyRepeat(pressedKeyView);
+                    break;
+                }
+
+                pressedKeyView = new PressedKeyView(mContext, getLabel(keyEvent));
+                mPressedKeys.put(identifier, pressedKeyView);
+                container.handleKeyPressed(pressedKeyView);
+                break;
+            }
+            case KeyEvent.ACTION_UP: {
+                if (pressedKeyView == null) {
+                    Slog.w(TAG, "Got key up for " + KeyEvent.keyCodeToString(keyEvent.getKeyCode())
+                            + " that was not tracked as being down.");
+                    break;
+                }
+                mPressedKeys.remove(identifier);
+                container.handleKeyRelease(pressedKeyView);
+                break;
+            }
+            default:
+                break;
+        }
+        keyEvent.recycle();
+    }
+
+    @VisibleForTesting
+    void handleRotaryInput(MotionEvent motionEvent) {
+        if (!showRotaryInput()) {
+            return;
+        }
+
+        float scrollAxisValue = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL);
+        mRotaryInputValueView.updateValue(scrollAxisValue);
+        mRotaryInputGraphView.addValue(scrollAxisValue, motionEvent.getEventTime());
+
+        motionEvent.recycle();
+    }
+
+    private static String getLabel(KeyEvent event) {
+        switch (event.getKeyCode()) {
+            case KeyEvent.KEYCODE_SPACE:
+                return "\u2423";
+            case KeyEvent.KEYCODE_TAB:
+                return "\u21e5";
+            case KeyEvent.KEYCODE_ENTER:
+            case KeyEvent.KEYCODE_NUMPAD_ENTER:
+                return "\u23CE";
+            case KeyEvent.KEYCODE_DEL:
+                return "\u232B";
+            case KeyEvent.KEYCODE_FORWARD_DEL:
+                return "\u2326";
+            case KeyEvent.KEYCODE_ESCAPE:
+                return "ESC";
+            case KeyEvent.KEYCODE_DPAD_UP:
+                return "\u2191";
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                return "\u2193";
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                return "\u2190";
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                return "\u2192";
+            case KeyEvent.KEYCODE_DPAD_UP_RIGHT:
+                return "\u2197";
+            case KeyEvent.KEYCODE_DPAD_UP_LEFT:
+                return "\u2196";
+            case KeyEvent.KEYCODE_DPAD_DOWN_RIGHT:
+                return "\u2198";
+            case KeyEvent.KEYCODE_DPAD_DOWN_LEFT:
+                return "\u2199";
+            default:
+                break;
+        }
+
+        final int unicodeChar = event.getUnicodeChar();
+        if (unicodeChar != 0) {
+            return new String(Character.toChars(unicodeChar));
+        }
+
+        final var label = KeyEvent.keyCodeToString(event.getKeyCode());
+        if (label.startsWith("KEYCODE_")) {
+            return label.substring(8);
+        }
+        return label;
+    }
+
+    /** Determine whether to show key presses by checking one of the key-related objects. */
+    private boolean showKeyPresses() {
+        return mPressedKeyContainer != null;
+    }
+
+    /** Determine whether to show rotary input by checking one of the rotary-related objects. */
+    private boolean showRotaryInput() {
+        return mRotaryInputValueView != null;
+    }
+
+    private static class PressedKeyView extends TextView {
+
+        private static final ColorFilter sInvertColors = new ColorMatrixColorFilter(new float[]{
+                -1.0f,     0,     0,    0, 255, // red
+                0, -1.0f,     0,    0, 255, // green
+                0,     0, -1.0f,    0, 255, // blue
+                0,     0,     0, 1.0f, 0    // alpha
+        });
+
+        PressedKeyView(Context c, String label) {
+            super(c);
+
+            final var dm = c.getResources().getDisplayMetrics();
+            final int keyViewSidePadding =
+                    (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, KEY_VIEW_SIDE_PADDING_DP, dm);
+            final int keyViewVerticalPadding =
+                    (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, KEY_VIEW_VERTICAL_PADDING_DP,
+                            dm);
+            final int keyViewMinWidth =
+                    (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, KEY_VIEW_MIN_WIDTH_DP, dm);
+            final int textSize =
+                    (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, KEY_VIEW_TEXT_SIZE_SP, dm);
+
+            setText(label);
+            setGravity(Gravity.CENTER);
+            setMinimumWidth(keyViewMinWidth);
+            setTextSize(textSize);
+            setTypeface(Typeface.SANS_SERIF);
+            setBackgroundResource(R.drawable.focus_event_pressed_key_background);
+            setPaddingRelative(keyViewSidePadding, keyViewVerticalPadding, keyViewSidePadding,
+                    keyViewVerticalPadding);
+
+            setHighlighted(true);
+        }
+
+        void setHighlighted(boolean isHighlighted) {
+            if (isHighlighted) {
+                setTextColor(Color.BLACK);
+                getBackground().setColorFilter(sInvertColors);
+            } else {
+                setTextColor(Color.WHITE);
+                getBackground().clearColorFilter();
+            }
+            invalidate();
+        }
+    }
+
+    private static class PressedKeyContainer extends LinearLayout {
+
+        private final MarginLayoutParams mPressedKeyLayoutParams;
+
+        PressedKeyContainer(Context c) {
+            super(c);
+
+            final var dm = c.getResources().getDisplayMetrics();
+            final int keySeparationMargin =
+                    (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, KEY_SEPARATION_MARGIN_DP, dm);
+
+            final var transition = new LayoutTransition();
+            transition.disableTransitionType(LayoutTransition.APPEARING);
+            transition.disableTransitionType(LayoutTransition.DISAPPEARING);
+            transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+            transition.setDuration(KEY_TRANSITION_DURATION_MILLIS);
+            setLayoutTransition(transition);
+
+            mPressedKeyLayoutParams = new MarginLayoutParams(WRAP_CONTENT, WRAP_CONTENT);
+            if (getOrientation() == VERTICAL) {
+                mPressedKeyLayoutParams.setMargins(0, keySeparationMargin, 0, 0);
+            } else {
+                mPressedKeyLayoutParams.setMargins(keySeparationMargin, 0, 0, 0);
+            }
+        }
+
+        public void handleKeyPressed(PressedKeyView pressedKeyView) {
+            addView(pressedKeyView, getChildCount(), mPressedKeyLayoutParams);
+            invalidate();
+        }
+
+        public void handleKeyRepeat(PressedKeyView repeatedKeyView) {
+            // Do nothing for now.
+        }
+
+        public void handleKeyRelease(PressedKeyView releasedKeyView) {
+            releasedKeyView.setHighlighted(false);
+            releasedKeyView.clearAnimation();
+            releasedKeyView.animate()
+                    .alpha(0)
+                    .setDuration(KEY_FADEOUT_DURATION_MILLIS)
+                    .setInterpolator(new AccelerateInterpolator())
+                    .withEndAction(this::cleanUpPressedKeyViews)
+                    .start();
+        }
+
+        private void cleanUpPressedKeyViews() {
+            int numChildrenToRemove = 0;
+            for (int i = 0; i < getChildCount(); i++) {
+                final View child = getChildAt(i);
+                if (child.getAlpha() != 0) {
+                    break;
+                }
+                child.setVisibility(View.GONE);
+                child.clearAnimation();
+                numChildrenToRemove++;
+            }
+            removeViews(0, numChildrenToRemove);
+            invalidate();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java b/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java
new file mode 100644
index 0000000..95635d9
--- /dev/null
+++ b/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2023 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.input.debug;
+
+import static android.util.TypedValue.COMPLEX_UNIT_SP;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Shows a graph with the rotary input values as a function of time.
+ * The graph gets reset if no action is received for a certain amount of time.
+ */
+public class RotaryInputGraphView extends View {
+
+    private static final int FRAME_COLOR = 0xbf741b47;
+    private static final int FRAME_WIDTH_SP = 2;
+    private static final int FRAME_BORDER_GAP_SP = 10;
+    private static final int FRAME_TEXT_SIZE_SP = 10;
+    private static final int FRAME_TEXT_OFFSET_SP = 2;
+    private static final int GRAPH_COLOR = 0xffff00ff;
+    private static final int GRAPH_LINE_WIDTH_SP = 1;
+    private static final int GRAPH_POINT_RADIUS_SP = 4;
+    private static final long MAX_SHOWN_TIME_INTERVAL = TimeUnit.SECONDS.toMillis(5);
+    private static final float DEFAULT_FRAME_CENTER_POSITION = 0;
+    private static final int MAX_GRAPH_VALUES_SIZE = 400;
+    /** Maximum time between values so that they are considered part of the same gesture. */
+    private static final long MAX_GESTURE_TIME = TimeUnit.SECONDS.toMillis(1);
+
+    private final DisplayMetrics mDm;
+    /**
+     * Distance in position units (amount scrolled in display pixels) from the center to the
+     * top/bottom frame lines.
+     */
+    private final float mFrameCenterToBorderDistance;
+    private final float mScaledVerticalScrollFactor;
+    private final Locale mDefaultLocale = Locale.getDefault();
+    private final Paint mFramePaint = new Paint();
+    private final Paint mFrameTextPaint = new Paint();
+    private final Paint mGraphLinePaint = new Paint();
+    private final Paint mGraphPointPaint = new Paint();
+
+    private final CyclicBuffer mGraphValues = new CyclicBuffer(MAX_GRAPH_VALUES_SIZE);
+    /** Position at which graph values are placed at the center of the graph. */
+    private float mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION;
+
+    public RotaryInputGraphView(Context c) {
+        super(c);
+
+        mDm = mContext.getResources().getDisplayMetrics();
+        // This makes the center-to-border distance equivalent to the display height, meaning
+        // that the total height of the graph is equivalent to 2x the display height.
+        mFrameCenterToBorderDistance = mDm.heightPixels;
+        mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor();
+
+        mFramePaint.setColor(FRAME_COLOR);
+        mFramePaint.setStrokeWidth(applyDimensionSp(FRAME_WIDTH_SP, mDm));
+
+        mFrameTextPaint.setColor(GRAPH_COLOR);
+        mFrameTextPaint.setTextSize(applyDimensionSp(FRAME_TEXT_SIZE_SP, mDm));
+
+        mGraphLinePaint.setColor(GRAPH_COLOR);
+        mGraphLinePaint.setStrokeWidth(applyDimensionSp(GRAPH_LINE_WIDTH_SP, mDm));
+        mGraphLinePaint.setStrokeCap(Paint.Cap.ROUND);
+        mGraphLinePaint.setStrokeJoin(Paint.Join.ROUND);
+
+        mGraphPointPaint.setColor(GRAPH_COLOR);
+        mGraphPointPaint.setStrokeWidth(applyDimensionSp(GRAPH_POINT_RADIUS_SP, mDm));
+        mGraphPointPaint.setStrokeCap(Paint.Cap.ROUND);
+        mGraphPointPaint.setStrokeJoin(Paint.Join.ROUND);
+    }
+
+    /**
+     * Reads new scroll axis value and updates the list accordingly. Old positions are
+     * kept at the front (what you would get with getFirst), while the recent positions are
+     * kept at the back (what you would get with getLast). Also updates the frame center
+     * position to handle out-of-bounds cases.
+     */
+    public void addValue(float scrollAxisValue, long eventTime) {
+        // Remove values that are too old.
+        while (mGraphValues.getSize() > 0
+                && (eventTime - mGraphValues.getFirst().mTime) > MAX_SHOWN_TIME_INTERVAL) {
+            mGraphValues.removeFirst();
+        }
+
+        // If there are no recent values, reset the frame center.
+        if (mGraphValues.getSize() == 0) {
+            mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION;
+        }
+
+        // Handle new value. We multiply the scroll axis value by the scaled scroll factor to
+        // get the amount of pixels to be scrolled. We also compute the accumulated position
+        // by adding the current value to the last one (if not empty).
+        final float displacement = scrollAxisValue * mScaledVerticalScrollFactor;
+        final float prevPos = (mGraphValues.getSize() == 0 ? 0 : mGraphValues.getLast().mPos);
+        final float pos = prevPos + displacement;
+
+        mGraphValues.add(pos, eventTime);
+
+        // The difference between the distance of the most recent position from the center
+        // frame (pos - mFrameCenterPosition) and the maximum allowed distance from the center
+        // frame (mFrameCenterToBorderDistance).
+        final float verticalDiff = Math.abs(pos - mFrameCenterPosition)
+                - mFrameCenterToBorderDistance;
+        // If needed, translate frame.
+        if (verticalDiff > 0) {
+            final int sign = pos - mFrameCenterPosition < 0 ? -1 : 1;
+            // Here, we update the center frame position by the exact amount needed for us to
+            // stay within the maximum allowed distance from the center frame.
+            mFrameCenterPosition += sign * verticalDiff;
+        }
+
+        // Redraw canvas.
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        // Note: vertical coordinates in Canvas go from top to bottom,
+        // that is bottomY > middleY > topY.
+        final int verticalMargin = applyDimensionSp(FRAME_BORDER_GAP_SP, mDm);
+        final int topY = verticalMargin;
+        final int bottomY = getHeight() - verticalMargin;
+        final int middleY = (topY + bottomY) / 2;
+
+        // Note: horizontal coordinates in Canvas go from left to right,
+        // that is rightX > leftX.
+        final int leftX = 0;
+        final int rightX = getWidth();
+
+        // Draw the frame, which includes 3 lines that show the maximum,
+        // minimum and middle positions of the graph.
+        canvas.drawLine(leftX, topY, rightX, topY, mFramePaint);
+        canvas.drawLine(leftX, middleY, rightX, middleY, mFramePaint);
+        canvas.drawLine(leftX, bottomY, rightX, bottomY, mFramePaint);
+
+        // Draw the position that each frame line corresponds to.
+        final int frameTextOffset = applyDimensionSp(FRAME_TEXT_OFFSET_SP, mDm);
+        canvas.drawText(
+                String.format(mDefaultLocale, "%.1f",
+                        mFrameCenterPosition + mFrameCenterToBorderDistance),
+                leftX,
+                topY - frameTextOffset, mFrameTextPaint
+        );
+        canvas.drawText(
+                String.format(mDefaultLocale, "%.1f", mFrameCenterPosition),
+                leftX,
+                middleY - frameTextOffset, mFrameTextPaint
+        );
+        canvas.drawText(
+                String.format(mDefaultLocale, "%.1f",
+                        mFrameCenterPosition - mFrameCenterToBorderDistance),
+                leftX,
+                bottomY - frameTextOffset, mFrameTextPaint
+        );
+
+        // If there are no graph values to be drawn, stop here.
+        if (mGraphValues.getSize() == 0) {
+            return;
+        }
+
+        // Draw the graph using the times and positions.
+        // We start at the most recent value (which should be drawn at the right) and move
+        // to the older values (which should be drawn to the left of more recent ones). Negative
+        // indices are handled by circuling back to the end of the buffer.
+        final long mostRecentTime = mGraphValues.getLast().mTime;
+        float prevCoordX = 0;
+        float prevCoordY = 0;
+        float prevAge = 0;
+        for (Iterator<GraphValue> iter = mGraphValues.reverseIterator(); iter.hasNext();) {
+            final GraphValue value = iter.next();
+
+            final int age = (int) (mostRecentTime - value.mTime);
+            final float pos = value.mPos;
+
+            // We get the horizontal coordinate in time units from left to right with
+            // (MAX_SHOWN_TIME_INTERVAL - age). Then, we rescale it to match the canvas
+            // units by dividing it by the time-domain length (MAX_SHOWN_TIME_INTERVAL)
+            // and by multiplying it by the canvas length (rightX - leftX). Finally, we
+            // offset the coordinate by adding it to leftX.
+            final float coordX = leftX + ((float) (MAX_SHOWN_TIME_INTERVAL - age)
+                    / MAX_SHOWN_TIME_INTERVAL) * (rightX - leftX);
+
+            // We get the vertical coordinate in position units from middle to top with
+            // (pos - mFrameCenterPosition). Then, we rescale it to match the canvas
+            // units by dividing it by half of the position-domain length
+            // (mFrameCenterToBorderDistance) and by multiplying it by half of the canvas
+            // length (middleY - topY). Finally, we offset the coordinate by subtracting
+            // it from middleY (we can't "add" here because the coordinate grows from top
+            // to bottom).
+            final float coordY = middleY - ((pos - mFrameCenterPosition)
+                    / mFrameCenterToBorderDistance) * (middleY - topY);
+
+            // Draw a point for this value.
+            canvas.drawPoint(coordX, coordY, mGraphPointPaint);
+
+            // If this value is part of the same gesture as the previous one, draw a line
+            // between them. We ignore the first value (with age = 0).
+            if (age != 0 && (age - prevAge) <= MAX_GESTURE_TIME) {
+                canvas.drawLine(prevCoordX, prevCoordY, coordX, coordY, mGraphLinePaint);
+            }
+
+            prevCoordX = coordX;
+            prevCoordY = coordY;
+            prevAge = age;
+        }
+    }
+
+    public float getFrameCenterPosition() {
+        return mFrameCenterPosition;
+    }
+
+    /**
+     * Converts a dimension in scaled pixel units to integer display pixels.
+     */
+    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) {
+        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm);
+    }
+
+    /**
+     * Holds data needed to draw each entry in the graph.
+     */
+    private static class GraphValue {
+        /** Position. */
+        float mPos;
+        /** Time when this value was added. */
+        long mTime;
+
+        GraphValue(float pos, long time) {
+            this.mPos = pos;
+            this.mTime = time;
+        }
+    }
+
+    /**
+     * Holds the graph values as a cyclic buffer. It has a fixed capacity, and it replaces the
+     * old values with new ones to avoid creating new objects.
+     */
+    private static class CyclicBuffer {
+        private final GraphValue[] mValues;
+        private final int mCapacity;
+        private int mSize = 0;
+        private int mLastIndex = 0;
+
+        // The iteration index and counter are here to make it easier to reset them.
+        /** Determines the value currently pointed by the iterator. */
+        private int mIteratorIndex;
+        /** Counts how many values have been iterated through. */
+        private int mIteratorCount;
+
+        /** Used traverse the values in reverse order. */
+        private final Iterator<GraphValue> mReverseIterator = new Iterator<GraphValue>() {
+            @Override
+            public boolean hasNext() {
+                return mIteratorCount <= mSize;
+            }
+
+            @Override
+            public GraphValue next() {
+                // Returns the value currently pointed by the iterator and moves the iterator to
+                // the previous one.
+                mIteratorCount++;
+                return mValues[(mIteratorIndex-- + mCapacity) % mCapacity];
+            }
+        };
+
+        CyclicBuffer(int capacity) {
+            mCapacity = capacity;
+            mValues = new GraphValue[capacity];
+        }
+
+        /**
+         * Add new graph value. If there is an existing object, we replace its data with the
+         * new one. With this, we re-use old objects instead of creating new ones.
+         */
+        void add(float pos, long time) {
+            mLastIndex = (mLastIndex + 1) % mCapacity;
+            if (mValues[mLastIndex] == null) {
+                mValues[mLastIndex] = new GraphValue(pos, time);
+            } else {
+                final GraphValue oldValue = mValues[mLastIndex];
+                oldValue.mPos = pos;
+                oldValue.mTime = time;
+            }
+
+            // If needed, account for new value in the buffer size.
+            if (mSize != mCapacity) {
+                mSize++;
+            }
+        }
+
+        int getSize() {
+            return mSize;
+        }
+
+        GraphValue getFirst() {
+            final int distanceBetweenLastAndFirst = (mCapacity - mSize) + 1;
+            final int firstIndex = (mLastIndex + distanceBetweenLastAndFirst) % mCapacity;
+            return mValues[firstIndex];
+        }
+
+        GraphValue getLast() {
+            return mValues[mLastIndex];
+        }
+
+        void removeFirst() {
+            mSize--;
+        }
+
+        /** Returns an iterator pointing at the last value. */
+        Iterator<GraphValue> reverseIterator() {
+            mIteratorIndex = mLastIndex;
+            mIteratorCount = 1;
+            return mReverseIterator;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/input/debug/RotaryInputValueView.java b/services/core/java/com/android/server/input/debug/RotaryInputValueView.java
new file mode 100644
index 0000000..9fadac5
--- /dev/null
+++ b/services/core/java/com/android/server/input/debug/RotaryInputValueView.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2023 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.input.debug;
+
+import static android.util.TypedValue.COMPLEX_UNIT_SP;
+
+import android.content.Context;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Typeface;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ViewConfiguration;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+import java.util.Locale;
+
+/**
+ * Draws the most recent rotary input value and indicates whether the source is active.
+ */
+public class RotaryInputValueView extends TextView {
+
+    private static final int INACTIVE_TEXT_COLOR = 0xffff00ff;
+    private static final int ACTIVE_TEXT_COLOR = 0xff420f28;
+    private static final int TEXT_SIZE_SP = 8;
+    private static final int SIDE_PADDING_SP = 4;
+    /** Determines how long the active status lasts. */
+    private static final int ACTIVE_STATUS_DURATION = 250 /* milliseconds */;
+    private static final ColorFilter ACTIVE_BACKGROUND_FILTER =
+            new ColorMatrixColorFilter(new float[]{
+                    0, 0, 0, 0, 255, // red
+                    0, 0, 0, 0,   0, // green
+                    0, 0, 0, 0, 255, // blue
+                    0, 0, 0, 0, 200  // alpha
+            });
+
+    private final Runnable mUpdateActivityStatusCallback = () -> updateActivityStatus(false);
+    private final float mScaledVerticalScrollFactor;
+    private final Locale mDefaultLocale = Locale.getDefault();
+
+    public RotaryInputValueView(Context c) {
+        super(c);
+
+        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+        mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor();
+
+        setText(getFormattedValue(0));
+        setTextColor(INACTIVE_TEXT_COLOR);
+        setTextSize(applyDimensionSp(TEXT_SIZE_SP, dm));
+        setPaddingRelative(applyDimensionSp(SIDE_PADDING_SP, dm), 0,
+                applyDimensionSp(SIDE_PADDING_SP, dm), 0);
+        setTypeface(null, Typeface.BOLD);
+        setBackgroundResource(R.drawable.focus_event_rotary_input_background);
+    }
+
+    /** Updates the shown text with the formatted value. */
+    public void updateValue(float value) {
+        removeCallbacks(mUpdateActivityStatusCallback);
+
+        setText(getFormattedValue(value * mScaledVerticalScrollFactor));
+
+        updateActivityStatus(true);
+        postDelayed(mUpdateActivityStatusCallback, ACTIVE_STATUS_DURATION);
+    }
+
+    /** Updates whether or not there's active rotary input. */
+    public void updateActivityStatus(boolean active) {
+        if (active) {
+            setTextColor(ACTIVE_TEXT_COLOR);
+            getBackground().setColorFilter(ACTIVE_BACKGROUND_FILTER);
+        } else {
+            setTextColor(INACTIVE_TEXT_COLOR);
+            getBackground().clearColorFilter();
+        }
+    }
+
+    private String getFormattedValue(float value) {
+        return String.format(mDefaultLocale, "%s%.1f", value < 0 ? "-" : "+", Math.abs(value));
+    }
+
+    /**
+     * Converts a dimension in scaled pixel units to integer display pixels.
+     */
+    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) {
+        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm);
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index 7726f40..dbbbed3 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -57,13 +57,13 @@
                 InputConfig.NOT_FOCUSABLE
                         | InputConfig.NOT_TOUCHABLE
                         | InputConfig.SPY
-                        | InputConfig.INTERCEPTS_STYLUS
-                        | InputConfig.TRUSTED_OVERLAY;
+                        | InputConfig.INTERCEPTS_STYLUS;
 
         // Configure the surface to receive stylus events across the entire display.
         mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
 
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE);
         t.setPosition(mInputSurface, 0, 0);
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 93c66a1..08cf3f7 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1431,13 +1431,17 @@
                 mContextHubWrapper.onBtMainSettingChanged(btEnabled);
             }
         } else {
-            Log.d(TAG, "BT adapter not available. Defaulting to disabled");
-            if (forceUpdate || mIsBtMainEnabled) {
-                mIsBtMainEnabled = false;
+            Log.d(TAG, "BT adapter not available. Getting permissions from user settings");
+            boolean btEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.BLUETOOTH_ON, 0) == 1;
+            boolean btScanEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
+            if (forceUpdate || mIsBtMainEnabled != btEnabled) {
+                mIsBtMainEnabled = btEnabled;
                 mContextHubWrapper.onBtMainSettingChanged(mIsBtMainEnabled);
             }
-            if (forceUpdate || mIsBtScanningEnabled) {
-                mIsBtScanningEnabled = false;
+            if (forceUpdate || mIsBtScanningEnabled != btScanEnabled) {
+                mIsBtScanningEnabled = btScanEnabled;
                 mContextHubWrapper.onBtScanningSettingChanged(mIsBtScanningEnabled);
             }
         }
diff --git a/services/core/java/com/android/server/media/AudioAttributesUtils.java b/services/core/java/com/android/server/media/AudioAttributesUtils.java
index b9c9bae..5d5d59b 100644
--- a/services/core/java/com/android/server/media/AudioAttributesUtils.java
+++ b/services/core/java/com/android/server/media/AudioAttributesUtils.java
@@ -48,6 +48,8 @@
             case AudioDeviceInfo.TYPE_DOCK_ANALOG:
                 return MediaRoute2Info.TYPE_DOCK;
             case AudioDeviceInfo.TYPE_HDMI:
+            case AudioDeviceInfo.TYPE_HDMI_ARC:
+            case AudioDeviceInfo.TYPE_HDMI_EARC:
                 return MediaRoute2Info.TYPE_HDMI;
             case AudioDeviceInfo.TYPE_USB_DEVICE:
                 return MediaRoute2Info.TYPE_USB_DEVICE;
@@ -81,6 +83,8 @@
             case AudioDeviceInfo.TYPE_DOCK:
             case AudioDeviceInfo.TYPE_DOCK_ANALOG:
             case AudioDeviceInfo.TYPE_HDMI:
+            case AudioDeviceInfo.TYPE_HDMI_ARC:
+            case AudioDeviceInfo.TYPE_HDMI_EARC:
             case AudioDeviceInfo.TYPE_USB_DEVICE:
                 return true;
             default:
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 83a3125..9dec1df 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -63,6 +63,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.media.flags.Flags;
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
 
@@ -161,11 +162,13 @@
         mPowerManager = mContext.getSystemService(PowerManager.class);
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
 
-        IntentFilter screenOnOffIntentFilter = new IntentFilter();
-        screenOnOffIntentFilter.addAction(ACTION_SCREEN_ON);
-        screenOnOffIntentFilter.addAction(ACTION_SCREEN_OFF);
+        if (!Flags.disableScreenOffBroadcastReceiver()) {
+            IntentFilter screenOnOffIntentFilter = new IntentFilter();
+            screenOnOffIntentFilter.addAction(ACTION_SCREEN_ON);
+            screenOnOffIntentFilter.addAction(ACTION_SCREEN_OFF);
+            mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter);
+        }
 
-        mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter);
         mContext.getPackageManager().addOnPermissionsChangeListener(this::onPermissionsChanged);
 
         MediaFeatureFlagManager.getInstance()
@@ -707,7 +710,8 @@
     }
 
     private boolean checkCallerHasSystemRoutingPermissions(int pid, int uid) {
-        return checkCallerHasModifyAudioRoutingPermission(pid, uid);
+        return checkCallerHasModifyAudioRoutingPermission(pid, uid)
+                || checkCallerHasBluetoothPermissions(pid, uid);
     }
 
     private boolean checkCallerHasModifyAudioRoutingPermission(int pid, int uid) {
@@ -2778,7 +2782,8 @@
             List<ManagerRecord> managerRecords = getManagerRecords();
 
             boolean isManagerScanning = false;
-            if (service.mPowerManager.isInteractive()) {
+            if (Flags.disableScreenOffBroadcastReceiver()
+                    || service.mPowerManager.isInteractive()) {
                 isManagerScanning = managerRecords.stream().anyMatch(manager ->
                         manager.mIsScanning && service.mActivityManager
                                 .getPackageImportance(manager.mOwnerPackageName)
diff --git a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
index 75a0cf5..6b7db2d 100644
--- a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
+++ b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
@@ -38,6 +38,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.media.AudioAttributes;
@@ -48,6 +49,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.VibrationEffect;
 import android.provider.Settings;
 import android.telephony.PhoneStateListener;
@@ -61,18 +63,21 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.EventLogTags;
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LogicalLight;
+import com.android.server.notification.Flags;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
@@ -87,15 +92,24 @@
     static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
             "debug.notification.interruptiveness", false);
 
+    private static final float DEFAULT_VOLUME = 1.0f;
+    // TODO (b/291899544): remove for release
+    private static final String POLITE_STRATEGY1 = "rule1";
+    private static final String POLITE_STRATEGY2 = "rule2";
+    private static final int DEFAULT_NOTIFICATION_COOLDOWN_ENABLED = 1;
+    private static final int DEFAULT_NOTIFICATION_COOLDOWN_ENABLED_FOR_WORK = 0;
+    private static final int DEFAULT_NOTIFICATION_COOLDOWN_ALL = 1;
+    private static final int DEFAULT_NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED = 0;
+
     private final Context mContext;
     private final PackageManager mPackageManager;
     private final TelephonyManager mTelephonyManager;
+    private final UserManager mUm;
     private final NotificationManagerPrivate mNMP;
     private final SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver;
     private AccessibilityManager mAccessibilityManager;
     private KeyguardManager mKeyguardManager;
     private AudioManager mAudioManager;
-    private final LightsManager mLightsManager;
     private final NotificationUsageStats mUsageStats;
     private final ZenModeHelper mZenModeHelper;
 
@@ -126,17 +140,26 @@
     private final float mInCallNotificationVolume;
     private Binder mCallNotificationToken = null;
 
+    // Settings flags
+    private boolean mNotificationCooldownEnabled;
+    private boolean mNotificationCooldownForWorkEnabled;
+    private boolean mNotificationCooldownApplyToAll;
+    private boolean mNotificationCooldownVibrateUnlocked;
+
+    private boolean mEnablePoliteNotificationsFeature;
+    private final PolitenessStrategy mStrategy;
+    private int mCurrentWorkProfileId = UserHandle.USER_NULL;
 
     public NotificationAttentionHelper(Context context, LightsManager lightsManager,
             AccessibilityManager accessibilityManager, PackageManager packageManager,
-            NotificationUsageStats usageStats,
+            UserManager userManager, NotificationUsageStats usageStats,
             NotificationManagerPrivate notificationManagerPrivate,
             ZenModeHelper zenModeHelper, SystemUiSystemPropertiesFlags.FlagResolver flagResolver) {
         mContext = context;
         mPackageManager = packageManager;
         mTelephonyManager = context.getSystemService(TelephonyManager.class);
         mAccessibilityManager = accessibilityManager;
-        mLightsManager = lightsManager;
+        mUm = userManager;
         mNMP = notificationManagerPrivate;
         mUsageStats = usageStats;
         mZenModeHelper = zenModeHelper;
@@ -144,8 +167,8 @@
 
         mVibratorHelper = new VibratorHelper(context);
 
-        mNotificationLight = mLightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
-        mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
+        mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
+        mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
 
         Resources resources = context.getResources();
         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
@@ -169,7 +192,39 @@
                 .build();
         mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
 
+        mEnablePoliteNotificationsFeature = Flags.politeNotifications();
+
+        if (mEnablePoliteNotificationsFeature) {
+            mStrategy = getPolitenessStrategy();
+        } else {
+            mStrategy = null;
+        }
+
         mSettingsObserver = new SettingsObserver();
+        loadUserSettings();
+    }
+
+    private PolitenessStrategy getPolitenessStrategy() {
+        final String politenessStrategy = mFlagResolver.getStringValue(
+                NotificationFlags.NOTIF_COOLDOWN_RULE);
+
+        if (POLITE_STRATEGY2.equals(politenessStrategy)) {
+            return new Strategy2(mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T1),
+                    mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T2),
+                    mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1),
+                    mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2));
+        } else {
+            if (!POLITE_STRATEGY1.equals(politenessStrategy)) {
+                Log.w(TAG, "Invalid cooldown strategy: " + politenessStrategy + ". Defaulting to "
+                        + POLITE_STRATEGY1);
+            }
+
+            return new Strategy1(mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T1),
+                    mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T2),
+                    mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1),
+                    mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2),
+                    mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET));
+        }
     }
 
     public void onSystemReady() {
@@ -202,11 +257,59 @@
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(Intent.ACTION_USER_PRESENT);
+        filter.addAction(Intent.ACTION_USER_ADDED);
+        filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
+        filter.addAction(Intent.ACTION_USER_UNLOCKED);
         mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
 
         mContext.getContentResolver().registerContentObserver(
                 SettingsObserver.NOTIFICATION_LIGHT_PULSE_URI, false, mSettingsObserver,
                 UserHandle.USER_ALL);
+        if (mEnablePoliteNotificationsFeature) {
+            mContext.getContentResolver().registerContentObserver(
+                    SettingsObserver.NOTIFICATION_COOLDOWN_ENABLED_URI, false, mSettingsObserver,
+                    UserHandle.USER_ALL);
+            mContext.getContentResolver().registerContentObserver(
+                    SettingsObserver.NOTIFICATION_COOLDOWN_ALL_URI, false, mSettingsObserver,
+                    UserHandle.USER_ALL);
+            mContext.getContentResolver().registerContentObserver(
+                    SettingsObserver.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED_URI, false,
+                    mSettingsObserver, UserHandle.USER_ALL);
+        }
+    }
+
+    private void loadUserSettings() {
+        if (mEnablePoliteNotificationsFeature) {
+            try {
+                mCurrentWorkProfileId = getManagedProfileId(ActivityManager.getCurrentUser());
+
+                mNotificationCooldownEnabled =
+                    Settings.System.getIntForUser(mContext.getContentResolver(),
+                        Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
+                        DEFAULT_NOTIFICATION_COOLDOWN_ENABLED, UserHandle.USER_CURRENT) != 0;
+                if (mCurrentWorkProfileId != UserHandle.USER_NULL) {
+                    mNotificationCooldownForWorkEnabled = Settings.System.getIntForUser(
+                        mContext.getContentResolver(),
+                        Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
+                        DEFAULT_NOTIFICATION_COOLDOWN_ENABLED_FOR_WORK, mCurrentWorkProfileId)
+                        != 0;
+                } else {
+                    mNotificationCooldownForWorkEnabled = false;
+                }
+                mNotificationCooldownApplyToAll = Settings.System.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.System.NOTIFICATION_COOLDOWN_ALL, DEFAULT_NOTIFICATION_COOLDOWN_ALL,
+                    UserHandle.USER_CURRENT) != 0;
+                mNotificationCooldownVibrateUnlocked = Settings.System.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED,
+                    DEFAULT_NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED,
+                    UserHandle.USER_CURRENT) != 0;
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to read Settings: " + e);
+            }
+        }
     }
 
     @VisibleForTesting
@@ -229,6 +332,10 @@
             Log.d(TAG, "buzzBeepBlinkLocked " + record);
         }
 
+        if (isPoliteNotificationFeatureEnabled(record)) {
+            mStrategy.onNotificationPosted(record);
+        }
+
         // Should this notification make noise, vibe, or use the LED?
         final boolean aboveThreshold =
                 mIsAutomotive
@@ -269,6 +376,9 @@
                     vibration = mVibratorHelper.createFallbackVibration(insistent);
                 }
                 hasValidVibrate = vibration != null;
+                // Vibration-only if unlocked and Settings flag set
+                boolean vibrateOnly =
+                        hasValidVibrate && mNotificationCooldownVibrateUnlocked && mUserPresent;
                 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
                 if (hasAudibleAlert && !shouldMuteNotificationLocked(record, signals)) {
                     if (!sentAccessibilityEvent) {
@@ -277,7 +387,7 @@
                     }
                     if (DEBUG) Slog.v(TAG, "Interrupting!");
                     boolean isInsistentUpdate = isInsistentUpdate(record);
-                    if (hasValidSound) {
+                    if (hasValidSound && !vibrateOnly) {
                         if (isInsistentUpdate) {
                             // don't reset insistent sound, it's jarring
                             beep = true;
@@ -301,7 +411,7 @@
                         if (isInsistentUpdate) {
                             buzz = true;
                         } else {
-                            buzz = playVibration(record, vibration, hasValidSound);
+                            buzz = playVibration(record, vibration, hasValidSound && !vibrateOnly);
                             if (buzz) {
                                 mVibrateNotificationKey = key;
                             }
@@ -341,9 +451,7 @@
         } else if (wasShowLights) {
             updateLightsLocked();
         }
-        final int buzzBeepBlink =
-                (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0);
-        if (buzzBeepBlink > 0) {
+        if (buzz || beep || blink) {
             // Ignore summary updates because we don't display most of the information.
             if (record.getSbn().isGroup() && record.getSbn().getNotification().isGroupSummary()) {
                 if (DEBUG_INTERRUPTIVENESS) {
@@ -362,15 +470,43 @@
                             + record.getKey() + " is interruptive: alerted");
                 }
             }
+        }
+        final int buzzBeepBlinkLoggingCode =
+                (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0) | getPoliteBit(record);
+        if (buzzBeepBlinkLoggingCode > 0) {
             MetricsLogger.action(record.getLogMaker()
                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
                     .setType(MetricsEvent.TYPE_OPEN)
-                    .setSubtype(buzzBeepBlink));
-            EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
+                    .setSubtype(buzzBeepBlinkLoggingCode));
+            EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0,
+                    getPolitenessState(record));
         }
         record.setAudiblyAlerted(buzz || beep);
+        if (mEnablePoliteNotificationsFeature) {
+            // Update last alert time
+            if (buzz || beep) {
+                record.getChannel().setLastNotificationUpdateTimeMs(System.currentTimeMillis());
+            }
+        }
+        return buzzBeepBlinkLoggingCode;
+    }
 
-        return buzzBeepBlink;
+    private int getPoliteBit(final NotificationRecord record) {
+        switch (getPolitenessState(record)) {
+            case PolitenessStrategy.POLITE_STATE_POLITE:
+                return MetricsProto.MetricsEvent.ALERT_POLITE;
+            case PolitenessStrategy.POLITE_STATE_MUTED:
+                return MetricsProto.MetricsEvent.ALERT_MUTED;
+            default:
+                return 0;
+        }
+    }
+
+    private int getPolitenessState(final NotificationRecord record) {
+        if (!isPoliteNotificationFeatureEnabled(record)) {
+            return PolitenessStrategy.POLITE_STATE_DEFAULT;
+        }
+        return mStrategy.getPolitenessState(record);
     }
 
     boolean isInsistentUpdate(final NotificationRecord record) {
@@ -468,7 +604,7 @@
                                 + record.getAudioAttributes());
                     }
                     player.playAsync(soundUri, record.getSbn().getUser(), looping,
-                            record.getAudioAttributes());
+                            record.getAudioAttributes(), getSoundVolume(record));
                     return true;
                 }
             } catch (RemoteException e) {
@@ -480,12 +616,56 @@
         return false;
     }
 
+    private boolean isPoliteNotificationFeatureEnabled(final NotificationRecord record) {
+        // Check feature flag
+        if (!mEnablePoliteNotificationsFeature) {
+            return false;
+        }
+
+        // The user can enable/disable notifications cooldown from the Settings app
+        if (!mNotificationCooldownEnabled) {
+            return false;
+        }
+
+        // The user can enable/disable notifications cooldown for work profile from the Settings app
+        if (isNotificationForWorkProfile(record) && !mNotificationCooldownForWorkEnabled) {
+            return false;
+        }
+
+        // The user can choose to apply cooldown for all apps/conversations only from the
+        // Settings app
+        if (!mNotificationCooldownApplyToAll && record.getChannel().getConversationId() == null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private float getSoundVolume(final NotificationRecord record) {
+        if (!isPoliteNotificationFeatureEnabled(record)) {
+            return DEFAULT_VOLUME;
+        }
+
+        return mStrategy.getSoundVolume(record);
+    }
+
+    private float getVibrationIntensity(final NotificationRecord record) {
+        if (!isPoliteNotificationFeatureEnabled(record)) {
+            return DEFAULT_VOLUME;
+        }
+
+        return mStrategy.getVibrationIntensity(record);
+    }
+
     private boolean playVibration(final NotificationRecord record, final VibrationEffect effect,
             boolean delayVibForSound) {
         // Escalate privileges so we can use the vibrator even if the
         // notifying app does not have the VIBRATE permission.
         final long identity = Binder.clearCallingIdentity();
         try {
+            final float scale = getVibrationIntensity(record);
+            final VibrationEffect scaledEffect = Float.compare(scale, DEFAULT_VOLUME) != 0
+                    ? mVibratorHelper.scale(effect, scale) : effect;
             if (delayVibForSound) {
                 new Thread(() -> {
                     // delay the vibration by the same amount as the notification sound
@@ -503,7 +683,7 @@
                     // so need to check that the notification is still valid for vibrate.
                     if (mNMP.getNotificationByKey(record.getKey()) != null) {
                         if (record.getKey().equals(mVibrateNotificationKey)) {
-                            vibrate(record, effect, true);
+                            vibrate(record, scaledEffect, true);
                         } else {
                             if (DEBUG) {
                                 Slog.v(TAG, "No vibration for notification "
@@ -517,7 +697,7 @@
                     }
                 }).start();
             } else {
-                vibrate(record, effect, false);
+                vibrate(record, scaledEffect, false);
             }
             return true;
         } finally {
@@ -535,7 +715,7 @@
     }
 
     void playInCallNotification() {
-        // TODO: Should we apply politeness to mInCallNotificationVolume ?
+        // TODO b/270456865: Should we apply politeness to mInCallNotificationVolume ?
         final ContentResolver cr = mContext.getContentResolver();
         if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
                 && Settings.Secure.getIntForUser(cr,
@@ -760,6 +940,22 @@
                 || signals.isCurrentProfile);
     }
 
+    private boolean isNotificationForWorkProfile(final NotificationRecord record) {
+        return (record.getUser().getIdentifier() == mCurrentWorkProfileId
+                && mCurrentWorkProfileId != UserHandle.USER_NULL);
+    }
+
+    private int getManagedProfileId(int parentUserId) {
+        final List<UserInfo> profiles = mUm.getProfiles(parentUserId);
+        for (UserInfo profile : profiles) {
+            if (profile.isManagedProfile()
+                    && profile.getUserHandle().getIdentifier() != parentUserId) {
+                return profile.getUserHandle().getIdentifier();
+            }
+        }
+        return UserHandle.USER_NULL;
+    }
+
     void sendAccessibilityEvent(NotificationRecord record) {
         if (!mAccessibilityManager.isEnabled()) {
             return;
@@ -791,6 +987,16 @@
         mAccessibilityManager.sendAccessibilityEvent(event);
     }
 
+    /**
+     * Notify the attention helper of a user interaction with a notification
+     * @param record that was interacted with
+     */
+    public void onUserInteraction(final NotificationRecord record) {
+        if (isPoliteNotificationFeatureEnabled(record)) {
+            mStrategy.onUserInteraction(record);
+        }
+    }
+
     public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
         pw.println("\n  Notification attention state:");
         pw.print(prefix);
@@ -834,6 +1040,243 @@
         }
     }
 
+    abstract private static class PolitenessStrategy {
+        static final int POLITE_STATE_DEFAULT = 0;
+        static final int POLITE_STATE_POLITE = 1;
+        static final int POLITE_STATE_MUTED = 2;
+
+        @IntDef(prefix = { "POLITE_STATE_" }, value = {
+                POLITE_STATE_DEFAULT,
+                POLITE_STATE_POLITE,
+                POLITE_STATE_MUTED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        @interface PolitenessState {}
+
+        protected final Map<String, Integer> mVolumeStates;
+
+        // Cooldown timer for transitioning into polite state
+        protected final int mTimeoutPolite;
+        // Cooldown timer for transitioning into muted state
+        protected final int mTimeoutMuted;
+        // Volume for polite state
+        protected final float mVolumePolite;
+        // Volume for muted state
+        protected final float mVolumeMuted;
+
+        public PolitenessStrategy(int timeoutPolite, int timeoutMuted, int volumePolite,
+                int volumeMuted) {
+            mVolumeStates = new HashMap<>();
+
+            this.mTimeoutPolite = timeoutPolite;
+            this.mTimeoutMuted = timeoutMuted;
+            this.mVolumePolite = volumePolite / 100.0f;
+            this.mVolumeMuted = volumeMuted / 100.0f;
+        }
+
+        abstract void onNotificationPosted(NotificationRecord record);
+
+        String getChannelKey(final NotificationRecord record) {
+            // use conversationId if it's a conversation
+            String channelId = record.getChannel().getConversationId() != null
+                    ? record.getChannel().getConversationId() : record.getChannel().getId();
+            return record.getSbn().getNormalizedUserId() + ":" + record.getSbn().getPackageName()
+                    + ":" + channelId;
+        }
+
+        public float getSoundVolume(final NotificationRecord record) {
+            float volume = DEFAULT_VOLUME;
+            final String key = getChannelKey(record);
+            final @PolitenessState int volState = getPolitenessState(record);
+
+            switch (volState) {
+                case POLITE_STATE_DEFAULT:
+                    volume = DEFAULT_VOLUME;
+                    break;
+                case POLITE_STATE_POLITE:
+                    volume = mVolumePolite;
+                    break;
+                case POLITE_STATE_MUTED:
+                    volume = mVolumeMuted;
+                    break;
+                default:
+                    Log.w(TAG, "getSoundVolume unexpected volume state: " + volState);
+                    break;
+            }
+
+            if (DEBUG) {
+                Log.i(TAG,
+                        "getSoundVolume state: " + volState + " vol: " + volume + " key: " + key);
+            }
+
+            return volume;
+        }
+
+        private float getVibrationIntensity(final NotificationRecord record) {
+            // TODO b/270456865: maybe use different scaling for vibration/sound ?
+            return getSoundVolume(record);
+        }
+
+        public void onUserInteraction(final NotificationRecord record) {
+            final String key = getChannelKey(record);
+            // reset to default state after user interaction
+            mVolumeStates.put(key, POLITE_STATE_DEFAULT);
+            record.getChannel().setLastNotificationUpdateTimeMs(0);
+        }
+
+        public final @PolitenessState int getPolitenessState(final NotificationRecord record) {
+            return mVolumeStates.getOrDefault(getChannelKey(record), POLITE_STATE_DEFAULT);
+        }
+    }
+
+    // TODO b/270456865: Only one of the two strategies will be released.
+    //  The other one need to be removed
+    /**
+     *  Polite notification strategy 1:
+     *   - Transitions from default (loud) => polite (lower volume) state if a notification
+     *  alerts the same channel before timeoutPolite.
+     *   - Transitions from polite => muted state if a notification alerts the same channel
+     *   before timeoutMuted OR transitions back to the default state if a notification alerts
+     *   after timeoutPolite.
+     *   - Transitions from muted => default state if the muted channel received more than maxPosted
+     *  notifications OR transitions back to the polite state if a notification alerts
+     *  after timeoutMuted.
+     *  - Transitions back to the default state after a user interaction with a notification.
+     */
+    public static class Strategy1 extends PolitenessStrategy {
+        // Keep track of the number of notifications posted per channel
+        private final Map<String, Integer> mNumPosted;
+        // Reset to default state if number of posted notifications exceed this value when muted
+        private final int mMaxPostedForReset;
+
+        public Strategy1(int timeoutPolite, int timeoutMuted, int volumePolite, int volumeMuted,
+                int maxPosted) {
+            super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted);
+
+            mNumPosted = new HashMap<>();
+            mMaxPostedForReset = maxPosted;
+
+            if (DEBUG) {
+                Log.i(TAG, "Strategy1: " + timeoutPolite + " " + timeoutMuted);
+            }
+        }
+
+        @Override
+        public void onNotificationPosted(final NotificationRecord record) {
+            long timeSinceLastNotif = System.currentTimeMillis()
+                    - record.getChannel().getLastNotificationUpdateTimeMs();
+
+            final String key = getChannelKey(record);
+            @PolitenessState int volState = getPolitenessState(record);
+
+            int numPosted = mNumPosted.getOrDefault(key, 0) + 1;
+            mNumPosted.put(key, numPosted);
+
+            switch (volState) {
+                case POLITE_STATE_DEFAULT:
+                    if (timeSinceLastNotif < mTimeoutPolite) {
+                        volState = POLITE_STATE_POLITE;
+                    }
+                    break;
+                case POLITE_STATE_POLITE:
+                    if (timeSinceLastNotif < mTimeoutMuted) {
+                        volState = POLITE_STATE_MUTED;
+                    } else if (timeSinceLastNotif > mTimeoutPolite) {
+                        volState = POLITE_STATE_DEFAULT;
+                    } else {
+                        volState = POLITE_STATE_POLITE;
+                    }
+                    break;
+                case POLITE_STATE_MUTED:
+                    if (timeSinceLastNotif > mTimeoutMuted) {
+                        volState = POLITE_STATE_POLITE;
+                    } else {
+                        volState = POLITE_STATE_MUTED;
+                    }
+                    if (numPosted >= mMaxPostedForReset) {
+                        volState = POLITE_STATE_DEFAULT;
+                        mNumPosted.put(key, 0);
+                    }
+                    break;
+                default:
+                    Log.w(TAG, "onNotificationPosted unexpected volume state: " + volState);
+                    break;
+            }
+
+            if (DEBUG) {
+                Log.i(TAG, "onNotificationPosted time delta: " + timeSinceLastNotif + " vol state: "
+                        + volState + " key: " + key + " numposted " + numPosted);
+            }
+
+            mVolumeStates.put(key, volState);
+        }
+
+        @Override
+        public void onUserInteraction(final NotificationRecord record) {
+            super.onUserInteraction(record);
+            mNumPosted.put(getChannelKey(record), 0);
+        }
+    }
+
+    /**
+     *  Polite notification strategy 2:
+     *   - Transitions from default (loud) => muted state if a notification
+     *   alerts the same channel before timeoutPolite.
+     *   - Transitions from polite => default state if a notification
+     *  alerts the same channel before timeoutMuted.
+     *   - Transitions from muted => default state if a notification alerts after timeoutMuted,
+     *  otherwise transitions to the polite state.
+     *   - Transitions back to the default state after a user interaction with a notification.
+     */
+    public static class Strategy2 extends PolitenessStrategy {
+        public Strategy2(int timeoutPolite, int timeoutMuted, int volumePolite, int volumeMuted) {
+            super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted);
+
+            if (DEBUG) {
+                Log.i(TAG, "Strategy2: " + timeoutPolite + " " + timeoutMuted);
+            }
+        }
+
+        @Override
+        public void onNotificationPosted(final NotificationRecord record) {
+            long timeSinceLastNotif = System.currentTimeMillis()
+                    - record.getChannel().getLastNotificationUpdateTimeMs();
+
+            final String key = getChannelKey(record);
+            @PolitenessState int volState = getPolitenessState(record);
+
+            switch (volState) {
+                case POLITE_STATE_DEFAULT:
+                    if (timeSinceLastNotif < mTimeoutPolite) {
+                        volState = POLITE_STATE_MUTED;
+                    }
+                    break;
+                case POLITE_STATE_POLITE:
+                    if (timeSinceLastNotif > mTimeoutMuted) {
+                        volState = POLITE_STATE_DEFAULT;
+                    }
+                    break;
+                case POLITE_STATE_MUTED:
+                    if (timeSinceLastNotif > mTimeoutMuted) {
+                        volState = POLITE_STATE_DEFAULT;
+                    } else {
+                        volState = POLITE_STATE_POLITE;
+                    }
+                    break;
+                default:
+                    Log.w(TAG, "onNotificationPosted unexpected volume state: " + volState);
+                    break;
+            }
+
+            if (DEBUG) {
+                Log.i(TAG, "onNotificationPosted time delta: " + timeSinceLastNotif + " vol state: "
+                        + volState + " key: " + key);
+            }
+
+            mVolumeStates.put(key, volState);
+        }
+    }
+
     //======================  Observers  =============================
     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -859,6 +1302,11 @@
                 if (mNotificationLight != null) {
                     mNotificationLight.turnOff();
                 }
+            } else if (action.equals(Intent.ACTION_USER_ADDED)
+                        || action.equals(Intent.ACTION_USER_REMOVED)
+                        || action.equals(Intent.ACTION_USER_SWITCHED)
+                        || action.equals(Intent.ACTION_USER_UNLOCKED)) {
+                loadUserSettings();
             }
         }
     };
@@ -867,6 +1315,12 @@
 
         private static final Uri NOTIFICATION_LIGHT_PULSE_URI = Settings.System.getUriFor(
                 Settings.System.NOTIFICATION_LIGHT_PULSE);
+        private static final Uri NOTIFICATION_COOLDOWN_ENABLED_URI = Settings.System.getUriFor(
+                Settings.System.NOTIFICATION_COOLDOWN_ENABLED);
+        private static final Uri NOTIFICATION_COOLDOWN_ALL_URI = Settings.System.getUriFor(
+                Settings.System.NOTIFICATION_COOLDOWN_ALL);
+        private static final Uri NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED_URI =
+                Settings.System.getUriFor(Settings.System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED);
         public SettingsObserver() {
             super(null);
         }
@@ -884,11 +1338,45 @@
                     updateLightsLocked();
                 }
             }
+            if (mEnablePoliteNotificationsFeature) {
+                if (NOTIFICATION_COOLDOWN_ENABLED_URI.equals(uri)) {
+                    mNotificationCooldownEnabled = Settings.System.getIntForUser(
+                            mContext.getContentResolver(),
+                            Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
+                            DEFAULT_NOTIFICATION_COOLDOWN_ENABLED,
+                            UserHandle.USER_CURRENT) != 0;
+
+                    if (mCurrentWorkProfileId != UserHandle.USER_NULL) {
+                        mNotificationCooldownForWorkEnabled = Settings.System.getIntForUser(
+                                mContext.getContentResolver(),
+                                Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
+                                DEFAULT_NOTIFICATION_COOLDOWN_ENABLED_FOR_WORK,
+                                mCurrentWorkProfileId)
+                                != 0;
+                    } else {
+                        mNotificationCooldownForWorkEnabled = false;
+                    }
+                }
+                if (NOTIFICATION_COOLDOWN_ALL_URI.equals(uri)) {
+                    mNotificationCooldownApplyToAll = Settings.System.getIntForUser(
+                            mContext.getContentResolver(),
+                            Settings.System.NOTIFICATION_COOLDOWN_ALL,
+                            DEFAULT_NOTIFICATION_COOLDOWN_ALL, UserHandle.USER_CURRENT)
+                            != 0;
+                }
+                if (NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED_URI.equals(uri)) {
+                    mNotificationCooldownVibrateUnlocked = Settings.System.getIntForUser(
+                            mContext.getContentResolver(),
+                            Settings.System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED,
+                            DEFAULT_NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED,
+                            UserHandle.USER_CURRENT) != 0;
+                }
+            }
         }
     }
 
 
-    //TODO: cleanup most (all?) of these
+    // TODO b/270456865: cleanup most (all?) of these
     //======================= FOR TESTS =====================
     @VisibleForTesting
     void setIsAutomotive(boolean isAutomotive) {
@@ -931,6 +1419,11 @@
     }
 
     @VisibleForTesting
+    void setUserPresent(boolean userPresent) {
+        mUserPresent = userPresent;
+    }
+
+    @VisibleForTesting
     void setLights(LogicalLight light) {
         mNotificationLight = light;
         mAttentionLight = light;
diff --git a/services/core/java/com/android/server/notification/NotificationBitmapJobService.java b/services/core/java/com/android/server/notification/NotificationBitmapJobService.java
index 4335a1d..e1a0707 100644
--- a/services/core/java/com/android/server/notification/NotificationBitmapJobService.java
+++ b/services/core/java/com/android/server/notification/NotificationBitmapJobService.java
@@ -29,7 +29,12 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 
-import java.util.Calendar;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZonedDateTime;
+import java.time.ZoneId;
 
 /**
  * This service runs everyday at 2am local time to remove expired bitmaps.
@@ -69,26 +74,25 @@
      * @return Milliseconds until the next time the job should run.
      */
     private static long getRunAfterMs() {
-        Calendar cal = Calendar.getInstance();  // Uses local time zone
-        final long now = cal.getTimeInMillis();
+        ZoneId zoneId = ZoneId.systemDefault();
+        ZonedDateTime now = Instant.now().atZone(zoneId);
 
-        cal.set(Calendar.HOUR_OF_DAY, 2);
-        cal.set(Calendar.MINUTE, 0);
-        cal.set(Calendar.MILLISECOND, 0);
-        final long today2AM = cal.getTimeInMillis();
+        LocalDate today = now.toLocalDate();
+        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0);
 
-        cal.add(Calendar.DAY_OF_YEAR, 1);
-        final long tomorrow2AM = cal.getTimeInMillis();
+        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId);
+        ZonedDateTime tomorrow2AM = today2AM.plusDays(1);
 
         return getTimeUntilRemoval(now, today2AM, tomorrow2AM);
     }
 
     @VisibleForTesting
-    static long getTimeUntilRemoval(long now, long today2AM, long tomorrow2AM) {
-        if (now < today2AM) {
-            return today2AM - now;
+    static long getTimeUntilRemoval(ZonedDateTime now, ZonedDateTime today2AM,
+                                    ZonedDateTime tomorrow2AM) {
+        if (Duration.between(now, today2AM).isNegative()) {
+            return Duration.between(now, tomorrow2AM).toMillis();
         }
-        return tomorrow2AM - now;
+        return Duration.between(now, today2AM).toMillis();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryJobService.java b/services/core/java/com/android/server/notification/NotificationHistoryJobService.java
index 3776ad7..c9317d1 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryJobService.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryJobService.java
@@ -27,6 +27,7 @@
 import android.os.CancellationSignal;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 
 import java.util.concurrent.TimeUnit;
@@ -77,5 +78,11 @@
         }
         return false;
     }
+
+    @Override
+    @VisibleForTesting
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+    }
 }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a3c71c2..837b761 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -396,7 +396,7 @@
     static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
     static final int MESSAGE_ON_PACKAGE_CHANGED = 8;
 
-    static final long BITMAP_EXPIRATION_TIME_MS = TimeUnit.HOURS.toMillis(24);
+    static final Duration BITMAP_DURATION = Duration.ofHours(24);
 
     // ranking thread messages
     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
@@ -541,6 +541,13 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
     private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L;
 
+    /**
+     * NO_CLEAR flag will be set for any media notification.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    static final long ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION = 264179692L;
+
     private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30);
 
     private IActivityManager mAm;
@@ -2525,7 +2532,7 @@
 
         if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
             mAttentionHelper = new NotificationAttentionHelper(getContext(), lightsManager,
-                mAccessibilityManager, mPackageManagerClient, usageStats,
+                mAccessibilityManager, mPackageManagerClient, userManager, usageStats,
                 mNotificationManagerPrivate, mZenModeHelper, flagResolver);
         }
 
@@ -3362,6 +3369,10 @@
         mAppUsageStats.reportEvent(r.getSbn().getPackageName(),
                 getRealUserId(r.getSbn().getUserId()),
                 UsageEvents.Event.USER_INTERACTION);
+
+        if (Flags.politeNotifications()) {
+            mAttentionHelper.onUserInteraction(r);
+        }
     }
 
     private int getRealUserId(int userId) {
@@ -5723,13 +5734,18 @@
         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
                 boolean granted, boolean userSet) {
             Objects.requireNonNull(listener);
+            if (UserHandle.getCallingUserId() != userId) {
+                getContext().enforceCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS,
+                        "setNotificationListenerAccessGrantedForUser for user " + userId);
+            }
             checkNotificationListenerAccess();
             if (granted && listener.flattenToString().length()
                     > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
                 throw new IllegalArgumentException(
                         "Component name too long: " + listener.flattenToString());
             }
-            if (!userSet && isNotificationListenerAccessUserSet(listener)) {
+            if (!userSet && isNotificationListenerAccessUserSet(listener, userId)) {
                 // Don't override user's choice
                 return;
             }
@@ -5755,9 +5771,8 @@
             }
         }
 
-        private boolean isNotificationListenerAccessUserSet(ComponentName listener) {
-            return mListeners.isPackageOrComponentUserSet(listener.flattenToString(),
-                    getCallingUserHandle().getIdentifier());
+        private boolean isNotificationListenerAccessUserSet(ComponentName listener, int userId) {
+            return mListeners.isPackageOrComponentUserSet(listener.flattenToString(), userId);
         }
 
         @Override
@@ -6698,7 +6713,7 @@
                     final long timePostedMs = r.getSbn().getPostTime();
                     final long timeNowMs = System.currentTimeMillis();
 
-                    if (isBitmapExpired(timePostedMs, timeNowMs, BITMAP_EXPIRATION_TIME_MS)) {
+                    if (isBitmapExpired(timePostedMs, timeNowMs, BITMAP_DURATION.toMillis())) {
                         removeBitmapAndRepost(r);
                     }
                 }
@@ -7189,6 +7204,12 @@
                             + "MEDIA_CONTENT_CONTROL permission");
                 }
             }
+
+            // Enforce NO_CLEAR flag on MediaStyle notification for apps with targetSdk >= V.
+            if (CompatChanges.isChangeEnabled(ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION,
+                    notificationUid)) {
+                notification.flags |= Notification.FLAG_NO_CLEAR;
+            }
         }
 
         // Ensure only allowed packages have a substitute app name
@@ -8599,7 +8620,7 @@
                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
                     .setType(MetricsEvent.TYPE_OPEN)
                     .setSubtype(buzzBeepBlink));
-            EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
+            EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0, 0);
         }
         record.setAudiblyAlerted(buzz || beep);
         return buzzBeepBlink;
@@ -8744,7 +8765,7 @@
                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
                             + " with attributes " + record.getAudioAttributes());
                     player.playAsync(soundUri, record.getSbn().getUser(), looping,
-                            record.getAudioAttributes());
+                            record.getAudioAttributes(), 1.0f);
                     return true;
                 }
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/notification/VibratorHelper.java b/services/core/java/com/android/server/notification/VibratorHelper.java
index e5d07bc..7204d05 100644
--- a/services/core/java/com/android/server/notification/VibratorHelper.java
+++ b/services/core/java/com/android/server/notification/VibratorHelper.java
@@ -50,6 +50,7 @@
     private final long[] mFallbackPattern;
     @Nullable private final float[] mDefaultPwlePattern;
     @Nullable private final float[] mFallbackPwlePattern;
+    private final int mDefaultVibrationAmplitude;
 
     public VibratorHelper(Context context) {
         mVibrator = context.getSystemService(Vibrator.class);
@@ -65,6 +66,8 @@
                 com.android.internal.R.array.config_defaultNotificationVibeWaveform);
         mFallbackPwlePattern = getFloatArray(context.getResources(),
                 com.android.internal.R.array.config_notificationFallbackVibeWaveform);
+        mDefaultVibrationAmplitude = context.getResources().getInteger(
+            com.android.internal.R.integer.config_defaultVibrationAmplitude);
     }
 
     /**
@@ -136,6 +139,14 @@
     }
 
     /**
+     *  Scale vibration effect, valid range is [0.0f, 1.0f]
+     *  Resolves default amplitude value if not already set.
+     */
+    public VibrationEffect scale(VibrationEffect effect, float scale) {
+        return effect.resolve(mDefaultVibrationAmplitude).scale(scale);
+    }
+
+    /**
      * Vibrate the device with given {@code effect}.
      *
      * <p>We need to vibrate as "android" so we can breakthrough DND.
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index f987629..79cd2a0 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -489,6 +489,9 @@
 
     boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId);
 
+    /** Check if the package is in a stopped state for a given user. */
+    boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId);
+
     boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId);
 
     @NonNull
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 5d2944e..7db7bf5 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -4938,7 +4938,7 @@
             int userId) {
         final int callingUid = Binder.getCallingUid();
         enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
-                false /* checkShell */, "isPackageSuspendedForUser for user " + userId);
+                false /* checkShell */, "when asking about packages for user " + userId);
         final PackageStateInternal ps = mSettings.getPackage(packageName);
         if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
             throw new IllegalArgumentException("Unknown target package: " + packageName);
@@ -4957,6 +4957,11 @@
     }
 
     @Override
+    public boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId) {
+        return getUserStageOrDefaultForUser(packageName, userId).isStopped();
+    }
+
+    @Override
     public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
             @UserIdInt int userId) {
         for (final PackageStateInternal packageState : getPackageStates().values()) {
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
index 76203ac..9a0306b 100644
--- a/services/core/java/com/android/server/pm/IPackageManagerBase.java
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -961,6 +961,12 @@
     }
 
     @Override
+    public final boolean isPackageStoppedForUser(@NonNull String packageName,
+            @UserIdInt int userId) {
+        return snapshot().isPackageStoppedForUser(packageName, userId);
+    }
+
+    @Override
     @Deprecated
     public final boolean isSafeMode() {
         // allow instant applications
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c6388e7..edb45aa 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import static android.content.pm.Flags.preventSdkLibApp;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
@@ -994,10 +995,11 @@
                         return;
                     }
                     final boolean isApex = (request.getScanFlags() & SCAN_AS_APEX) != 0;
-                    if (!isApex) {
-                        createdAppId.put(packageName, optimisticallyRegisterAppId(request));
-                    } else {
+                    final boolean isSdkLibrary = packageToScan.isSdkLibrary();
+                    if (isApex || (isSdkLibrary && preventSdkLibApp())) {
                         request.getScannedPackageSetting().setAppId(Process.INVALID_UID);
+                    } else {
+                        createdAppId.put(packageName, optimisticallyRegisterAppId(request));
                     }
                     versionInfos.put(packageName,
                             mPm.getSettingsVersionForPackage(packageToScan));
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 1c7024b..2d19282 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -22,8 +22,6 @@
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 import static android.os.Process.INVALID_UID;
 
-import static com.android.server.art.model.DexoptResult.DexContainerFileDexoptResult;
-import static com.android.server.art.model.DexoptResult.PackageDexoptResult;
 import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
 import static com.android.server.pm.PackageManagerService.TAG;
@@ -58,7 +56,6 @@
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.LinkedHashSet;
 import java.util.List;
 
 final class InstallRequest {
@@ -150,9 +147,6 @@
     @NonNull
     private int[] mUpdateBroadcastInstantUserIds = EMPTY_INT_ARRAY;
 
-    @NonNull
-    private ArrayList<String> mWarnings = new ArrayList<>();
-
     // New install
     InstallRequest(InstallingSession params) {
         mUserId = params.getUser().getIdentifier();
@@ -664,11 +658,6 @@
         return mUpdateBroadcastInstantUserIds;
     }
 
-    @NonNull
-    public ArrayList<String> getWarnings() {
-        return mWarnings;
-    }
-
     public void setScanFlags(int scanFlags) {
         mScanFlags = scanFlags;
     }
@@ -866,10 +855,6 @@
         }
     }
 
-    public void addWarning(@NonNull String warning) {
-        mWarnings.add(warning);
-    }
-
     public void onPrepareStarted() {
         if (mPackageMetrics != null) {
             mPackageMetrics.onStepStarted(PackageMetrics.STEP_PREPARE);
@@ -919,37 +904,22 @@
     }
 
     public void onDexoptFinished(DexoptResult dexoptResult) {
-        // Only report external profile warnings when installing from adb. The goal is to warn app
-        // developers if they have provided bad external profiles, so it's not beneficial to report
-        // those warnings in the normal app install workflow.
-        if (isInstallFromAdb()) {
-            var externalProfileErrors = new LinkedHashSet<String>();
-            for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) {
-                for (DexContainerFileDexoptResult fileResult :
-                        packageResult.getDexContainerFileDexoptResults()) {
-                    externalProfileErrors.addAll(fileResult.getExternalProfileErrors());
-                }
-            }
-            if (!externalProfileErrors.isEmpty()) {
-                addWarning("Error occurred during dexopt when processing external profiles:\n  "
-                        + String.join("\n  ", externalProfileErrors));
+        if (mPackageMetrics == null) {
+            return;
+        }
+        mDexoptStatus = dexoptResult.getFinalStatus();
+        if (mDexoptStatus != DexoptResult.DEXOPT_PERFORMED) {
+            return;
+        }
+        long durationMillis = 0;
+        for (DexoptResult.PackageDexoptResult packageResult :
+                dexoptResult.getPackageDexoptResults()) {
+            for (DexoptResult.DexContainerFileDexoptResult fileResult :
+                    packageResult.getDexContainerFileDexoptResults()) {
+                durationMillis += fileResult.getDex2oatWallTimeMillis();
             }
         }
-
-        // Report dexopt metrics.
-        if (mPackageMetrics != null) {
-            mDexoptStatus = dexoptResult.getFinalStatus();
-            if (mDexoptStatus == DexoptResult.DEXOPT_PERFORMED) {
-                long durationMillis = 0;
-                for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) {
-                    for (DexContainerFileDexoptResult fileResult :
-                            packageResult.getDexContainerFileDexoptResults()) {
-                        durationMillis += fileResult.getDex2oatWallTimeMillis();
-                    }
-                }
-                mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis);
-            }
-        }
+        mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis);
     }
 
     public void onInstallCompleted() {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 11660a59..a161e8c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -107,19 +107,22 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.SizedInputStream;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
+import java.io.DataInputStream;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
 import java.nio.file.attribute.PosixFilePermission;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -130,6 +133,8 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.function.BiConsumer;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
@@ -216,6 +221,7 @@
         private final ShortcutChangeHandler mShortcutChangeHandler;
 
         private final Handler mCallbackHandler;
+        private final ExecutorService mOnDumpExecutor = Executors.newSingleThreadExecutor();
 
         private PackageInstallerService mPackageInstallerService;
 
@@ -1512,7 +1518,7 @@
                     forEachViewCaptureWindow((fileName, is) -> {
                         try {
                             zipOs.putNextEntry(new ZipEntry("FS" + fileName));
-                            is.transferTo(zipOs);
+                            transferViewCaptureData(is, zipOs);
                             zipOs.closeEntry();
                         } catch (IOException e) {
                             getErrPrintWriter().write("Failed to output " + fileName
@@ -1553,8 +1559,9 @@
         private void dumpViewCaptureDataToWmTrace(@NonNull String fileName,
                 @NonNull InputStream is) {
             Path outPath = Paths.get(fileName);
-            try {
-                Files.copy(is, outPath, StandardCopyOption.REPLACE_EXISTING);
+            try (OutputStream os = Files.newOutputStream(outPath, StandardOpenOption.CREATE,
+                    StandardOpenOption.TRUNCATE_EXISTING)) {
+                transferViewCaptureData(is, os);
                 Files.setPosixFilePermissions(outPath, WM_TRACE_FILE_PERMISSIONS);
             } catch (IOException e) {
                 Log.d(TAG, "failed to write data to " + fileName + " in wmtrace dir", e);
@@ -1562,6 +1569,15 @@
         }
 
         /**
+         * Raw input stream reads hang on the final read when transferring data in via the pipe.
+         * The fix used below is to count and read the exact amount of bytes being sent.
+         */
+        private void transferViewCaptureData(InputStream is, OutputStream os) throws IOException {
+            DataInputStream dataInputStream = new DataInputStream(is);
+            new SizedInputStream(dataInputStream, dataInputStream.readInt()).transferTo(os);
+        }
+
+        /**
          * IDumpCallback.onDump alerts the in-process ViewCapture instance to start sending data
          * to LauncherAppsService via the pipe's input provided. This data (as well as an output
          * file name) is provided to the consumer via an InputStream to output where it wants (for
@@ -1569,24 +1585,37 @@
          */
         private void forEachViewCaptureWindow(
                 @NonNull BiConsumer<String, InputStream> outputtingConsumer) {
-            for (int i = mDumpCallbacks.beginBroadcast() - 1; i >= 0; i--) {
-                String packageName = (String) mDumpCallbacks.getBroadcastCookie(i);
-                String fileName = WM_TRACE_DIR + packageName + "_" + i + VC_FILE_SUFFIX;
+            try {
+                // This multi-threading prevents ctrl-C command line command aborting from putting
+                // the mDumpCallbacks RemoteCallbackList in a bad Broadcast state. We need to wait
+                // for it to complete even though it is on a background thread.
+                mOnDumpExecutor.submit(() -> {
+                    try {
+                        for (int i = mDumpCallbacks.beginBroadcast() - 1; i >= 0; i--) {
+                            String packageName = (String) mDumpCallbacks.getBroadcastCookie(i);
+                            String fileName = WM_TRACE_DIR + packageName + "_" + i + VC_FILE_SUFFIX;
 
-                try {
-                    // Order is important here. OnDump needs to be called before the BiConsumer
-                    // accepts & starts blocking on reading the input stream.
-                    ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
-                    mDumpCallbacks.getBroadcastItem(i).onDump(pipe[1]);
+                            try {
+                                // Order is important here. OnDump needs to be called before the
+                                // BiConsumer accepts & starts blocking on reading the input stream.
+                                ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+                                mDumpCallbacks.getBroadcastItem(i).onDump(pipe[1]);
 
-                    InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0]);
-                    outputtingConsumer.accept(fileName, is);
-                    is.close();
-                } catch (Exception e) {
-                    Log.d(TAG, "failed to pipe view capture data", e);
-                }
+                                InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
+                                        pipe[0]);
+                                outputtingConsumer.accept(fileName, is);
+                                is.close();
+                            } catch (Exception e) {
+                                Log.d(TAG, "failed to pipe view capture data", e);
+                            }
+                        }
+                    } finally {
+                        mDumpCallbacks.finishBroadcast();
+                    }
+                }).get();
+            } catch (InterruptedException | ExecutionException e) {
+                Log.e(TAG, "background work was interrupted", e);
             }
-            mDumpCallbacks.finishBroadcast();
         }
 
         @RequiresPermission(READ_FRAME_BUFFER)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d0e5f96..6627039 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2930,40 +2930,15 @@
      * @return a future that will be completed when the whole process is completed.
      */
     private CompletableFuture<Void> install() {
-        // `futures` either contains only one session (`this`) or contains one parent session
-        // (`this`) and n-1 child sessions.
         List<CompletableFuture<InstallResult>> futures = installNonStaged();
         CompletableFuture<InstallResult>[] arr = new CompletableFuture[futures.size()];
         return CompletableFuture.allOf(futures.toArray(arr)).whenComplete((r, t) -> {
             if (t == null) {
                 setSessionApplied();
-                var multiPackageWarnings = new ArrayList<String>();
-                if (isMultiPackage()) {
-                    // This is a parent session. Collect warnings from children.
-                    for (CompletableFuture<InstallResult> f : futures) {
-                        InstallResult result = f.join();
-                        if (result.session != this && result.extras != null) {
-                            ArrayList<String> childWarnings = result.extras.getStringArrayList(
-                                    PackageInstaller.EXTRA_WARNINGS);
-                            if (!ArrayUtils.isEmpty(childWarnings)) {
-                                multiPackageWarnings.addAll(childWarnings);
-                            }
-                        }
-                    }
-                }
                 for (CompletableFuture<InstallResult> f : futures) {
                     InstallResult result = f.join();
-                    Bundle extras = result.extras;
-                    if (isMultiPackage() && result.session == this
-                            && !multiPackageWarnings.isEmpty()) {
-                        if (extras == null) {
-                            extras = new Bundle();
-                        }
-                        extras.putStringArrayList(
-                                PackageInstaller.EXTRA_WARNINGS, multiPackageWarnings);
-                    }
                     result.session.dispatchSessionFinished(
-                            INSTALL_SUCCEEDED, "Session installed", extras);
+                            INSTALL_SUCCEEDED, "Session installed", result.extras);
                 }
             } else {
                 PackageManagerException e = (PackageManagerException) t.getCause();
@@ -5214,10 +5189,6 @@
             if (!TextUtils.isEmpty(existing)) {
                 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
             }
-            ArrayList<String> warnings = extras.getStringArrayList(PackageInstaller.EXTRA_WARNINGS);
-            if (!ArrayUtils.isEmpty(warnings)) {
-                fillIn.putStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS, warnings);
-            }
         }
         try {
             final BroadcastOptions options = BroadcastOptions.makeBasic();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ddc8369..6260dd5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1434,9 +1434,6 @@
                 break;
             }
         }
-        if (!request.getWarnings().isEmpty()) {
-            extras.putStringArrayList(PackageInstaller.EXTRA_WARNINGS, request.getWarnings());
-        }
         return extras;
     }
 
@@ -4501,6 +4498,7 @@
             boolean stopped, @UserIdInt int userId) {
         if (!mUserManager.exists(userId)) return;
         final int callingUid = Binder.getCallingUid();
+        boolean wasStopped = false;
         if (snapshot.getInstantAppPackageName(callingUid) == null) {
             final int permission = mContext.checkCallingOrSelfPermission(
                     Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
@@ -4522,6 +4520,7 @@
                     ? null : packageState.getUserStateOrDefault(userId);
             if (packageState != null && packageUserState.isStopped() != stopped) {
                 boolean wasNotLaunched = packageUserState.isNotLaunched();
+                wasStopped = packageUserState.isStopped();
                 commitPackageStateMutation(null, packageName, state -> {
                     PackageUserStateWrite userState = state.userState(userId);
                     userState.setStopped(stopped);
@@ -4553,6 +4552,24 @@
                     ah.setHibernatingGlobally(packageName, false);
                 }
             });
+            // Send UNSTOPPED broadcast if necessary
+            if (wasStopped && Flags.stayStopped()) {
+                final PackageManagerInternal pmi =
+                        mInjector.getLocalService(PackageManagerInternal.class);
+                final int [] userIds = resolveUserIds(userId);
+                final SparseArray<int[]> broadcastAllowList =
+                        snapshotComputer().getVisibilityAllowLists(packageName, userIds);
+                final Bundle extras = new Bundle();
+                extras.putInt(Intent.EXTRA_UID, pmi.getPackageUid(packageName, 0, userId));
+                extras.putInt(Intent.EXTRA_USER_HANDLE, userId);
+                mHandler.post(() -> {
+                    mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_UNSTOPPED,
+                            packageName, extras,
+                            Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
+                            userIds, null, broadcastAllowList, null,
+                            null);
+                });
+            }
         }
     }
 
@@ -6929,6 +6946,25 @@
         public ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions(int userId) {
             return mInstallerService.getHistoricalSessions(userId);
         }
+
+        @Override
+        public void sendPackageRestartedBroadcast(@NonNull String packageName,
+                int uid, @Intent.Flags int flags) {
+            final int userId = UserHandle.getUserId(uid);
+            final int [] userIds = resolveUserIds(userId);
+            final SparseArray<int[]> broadcastAllowList =
+                    snapshotComputer().getVisibilityAllowLists(packageName, userIds);
+            final Bundle extras = new Bundle();
+            extras.putInt(Intent.EXTRA_UID, uid);
+            extras.putInt(Intent.EXTRA_USER_HANDLE, userId);
+            mHandler.post(() -> {
+                mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_RESTARTED,
+                        packageName, extras,
+                        flags, null, null,
+                        userIds, null, broadcastAllowList, null,
+                        null);
+            });
+        }
     }
 
     private void setEnabledOverlayPackages(@UserIdInt int userId,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 7264e2e..3a9272d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -4397,21 +4397,10 @@
             session.commit(receiver.getIntentSender());
             if (!session.isStaged()) {
                 final Intent result = receiver.getResult();
-                int status = result.getIntExtra(
-                        PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
-                List<String> warnings =
-                        result.getStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS);
+                final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                        PackageInstaller.STATUS_FAILURE);
                 if (status == PackageInstaller.STATUS_SUCCESS) {
-                    if (!ArrayUtils.isEmpty(warnings)) {
-                        // Don't start the output string with "Success" because that will make adb
-                        // treat this as a success.
-                        for (String warning : warnings) {
-                            pw.println("Warning: " + warning);
-                        }
-                        // Treat warnings as failure to draw app developers' attention.
-                        status = PackageInstaller.STATUS_FAILURE;
-                        pw.println("Completed with warning(s)");
-                    } else if (logSuccess) {
+                    if (logSuccess) {
                         pw.println("Success");
                     }
                 } else {
diff --git a/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java b/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
index b8c2b86..1f12c88 100644
--- a/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
+++ b/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
@@ -50,7 +50,7 @@
 
     @NonNull
     private final Object mLock = new Object();
-    final IActivityManager mActivityManager = ActivityManager.getService();
+    IActivityManager mActivityManager;
 
     @NonNull
     @GuardedBy("mLock")
@@ -149,6 +149,9 @@
         try {
             final int[] resolvedUserIds;
             if (userIds == null) {
+                if (mActivityManager == null) {
+                    mActivityManager = ActivityManager.getService();
+                }
                 if (mActivityManager == null) return;
                 resolvedUserIds = mActivityManager.getRunningUserIds();
             } else {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 82d3e91..0e98158 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -75,13 +75,13 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.multiuser.Flags;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Environment;
 import android.os.FileUtils;
-import android.os.Flags;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IProgressListener;
@@ -286,6 +286,8 @@
 
     private static final int USER_VERSION = 11;
 
+    private static final int MAX_USER_STRING_LENGTH = 500;
+
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
     static final int WRITE_USER_MSG = 1;
@@ -1557,7 +1559,7 @@
         logQuietModeEnabled(userId, enableQuietMode, callingPackage);
 
         // Broadcast generic intents for all profiles
-        if (Flags.allowPrivateProfile()) {
+        if (android.os.Flags.allowPrivateProfile()) {
             broadcastProfileAvailabilityChanges(profile, parent.getUserHandle(),
                     enableQuietMode, false);
         }
@@ -3783,6 +3785,8 @@
 
     @GuardedBy({"mPackagesLock"})
     private void readUserListLP() {
+        // Whether guest restrictions are present on userlist.xml
+        boolean guestRestrictionsArePresentOnUserListXml = false;
         try (ResilientAtomicFile file = getUserListFile()) {
             FileInputStream fin = null;
             try {
@@ -3832,6 +3836,7 @@
                                 }
                             }
                         } else if (name.equals(TAG_GUEST_RESTRICTIONS)) {
+                            guestRestrictionsArePresentOnUserListXml = true;
                             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                                     && type != XmlPullParser.END_TAG) {
                                 if (type == XmlPullParser.START_TAG) {
@@ -3850,6 +3855,7 @@
 
                 updateUserIds();
                 upgradeIfNecessaryLP();
+                updateUsersWithFeatureFlags(guestRestrictionsArePresentOnUserListXml);
             } catch (Exception e) {
                 // Remove corrupted file and retry.
                 file.failRead(fin, e);
@@ -3875,6 +3881,24 @@
     }
 
     /**
+     * Update any user formats or Xml data that need to be updated based on the current user state
+     * and the feature flag settings.
+     */
+    @GuardedBy({"mPackagesLock"})
+    private void updateUsersWithFeatureFlags(boolean guestRestrictionsArePresentOnUserListXml) {
+        // User Xml re-writes are required when guest restrictions are saved on userlist.xml but
+        // as per the feature flag it should be on the SYSTEM user's xml or guest restrictions
+        // are saved on SYSTEM user's xml but as per the flags it should not be saved there.
+        if (guestRestrictionsArePresentOnUserListXml
+                == Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) {
+            for (int userId: getUserIds()) {
+                writeUserLP(getUserDataNoChecks(userId));
+            }
+            writeUserListLP();
+        }
+    }
+
+    /**
      * Version of {@link #upgradeIfNecessaryLP()} that takes in the userVersion for testing
      * purposes. For non-tests, use {@link #upgradeIfNecessaryLP()}.
      */
@@ -4374,24 +4398,41 @@
         // Write seed data
         if (userData.persistSeedData) {
             if (userData.seedAccountName != null) {
-                serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, userData.seedAccountName);
+                serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME,
+                        truncateString(userData.seedAccountName));
             }
             if (userData.seedAccountType != null) {
-                serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
+                serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE,
+                        truncateString(userData.seedAccountType));
             }
         }
         if (userInfo.name != null) {
             serializer.startTag(null, TAG_NAME);
-            serializer.text(userInfo.name);
+            serializer.text(truncateString(userInfo.name));
             serializer.endTag(null, TAG_NAME);
         }
         synchronized (mRestrictionsLock) {
             UserRestrictionsUtils.writeRestrictions(serializer,
                     mBaseUserRestrictions.getRestrictions(userInfo.id), TAG_RESTRICTIONS);
 
-            UserRestrictionsUtils.writeRestrictions(serializer,
-                    mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL),
-                    TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS);
+            if (Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) {
+                if (userInfo.id == UserHandle.USER_SYSTEM) {
+                    UserRestrictionsUtils.writeRestrictions(serializer,
+                            mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL),
+                            TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS);
+
+                    serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
+                    synchronized (mGuestRestrictions) {
+                        UserRestrictionsUtils.writeRestrictions(serializer, mGuestRestrictions,
+                                TAG_RESTRICTIONS);
+                    }
+                    serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
+                }
+            } else {
+                UserRestrictionsUtils.writeRestrictions(serializer,
+                        mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL),
+                        TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS);
+            }
 
             UserRestrictionsUtils.writeRestrictions(serializer,
                     mDevicePolicyUserRestrictions.getRestrictions(userInfo.id),
@@ -4431,6 +4472,13 @@
         serializer.endDocument();
     }
 
+    private String truncateString(String original) {
+        if (original == null || original.length() <= MAX_USER_STRING_LENGTH) {
+            return original;
+        }
+        return original.substring(0, MAX_USER_STRING_LENGTH);
+    }
+
     /*
      * Writes the user list file in this format:
      *
@@ -4460,12 +4508,15 @@
                 serializer.attributeInt(null, ATTR_USER_VERSION, mUserVersion);
                 serializer.attributeInt(null, ATTR_USER_TYPE_VERSION, mUserTypeVersion);
 
-                serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
-                synchronized (mGuestRestrictions) {
-                    UserRestrictionsUtils
-                            .writeRestrictions(serializer, mGuestRestrictions, TAG_RESTRICTIONS);
+                if (!Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) {
+                    serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
+                    synchronized (mGuestRestrictions) {
+                        UserRestrictionsUtils
+                                .writeRestrictions(serializer, mGuestRestrictions,
+                                        TAG_RESTRICTIONS);
+                    }
+                    serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
                 }
-                serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
                 int[] userIdsToWrite;
                 synchronized (mUsersLock) {
                     userIdsToWrite = new int[mUsers.size()];
@@ -4609,6 +4660,19 @@
                     localRestrictions = UserRestrictionsUtils.readRestrictions(parser);
                 } else if (TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS.equals(tag)) {
                     globalRestrictions = UserRestrictionsUtils.readRestrictions(parser);
+                } else if (TAG_GUEST_RESTRICTIONS.equals(tag)) {
+                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                            && type != XmlPullParser.END_TAG) {
+                        if (type == XmlPullParser.START_TAG) {
+                            if (parser.getName().equals(TAG_RESTRICTIONS)) {
+                                synchronized (mGuestRestrictions) {
+                                    UserRestrictionsUtils
+                                            .readRestrictions(parser, mGuestRestrictions);
+                                }
+                            }
+                            break;
+                        }
+                    }
                 } else if (TAG_ACCOUNT.equals(tag)) {
                     type = parser.next();
                     if (type == XmlPullParser.TEXT) {
@@ -4869,7 +4933,7 @@
             @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,
             @NonNull TimingsTraceAndSlog t, @Nullable Object token)
             throws UserManager.CheckedUserOperationException {
-
+        String truncatedName = truncateString(name);
         final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
         if (userTypeDetails == null) {
             throwCheckedUserOperationException(
@@ -4904,8 +4968,8 @@
 
         // Try to use a pre-created user (if available).
         if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) {
-            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name,
-                    token);
+            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags,
+                    truncatedName, token);
             if (preCreatedUser != null) {
                 return preCreatedUser;
             }
@@ -5000,7 +5064,7 @@
                         flags |= UserInfo.FLAG_EPHEMERAL_ON_CREATE;
                     }
 
-                    userInfo = new UserInfo(userId, name, null, flags, userType);
+                    userInfo = new UserInfo(userId, truncatedName, null, flags, userType);
                     userInfo.serialNumber = mNextSerialNumber++;
                     userInfo.creationTime = getCreationTime();
                     userInfo.partial = true;
@@ -6456,8 +6520,8 @@
                     Slog.e(LOG_TAG, "No such user for settings seed data u=" + userId);
                     return;
                 }
-                userData.seedAccountName = accountName;
-                userData.seedAccountType = accountType;
+                userData.seedAccountName = truncateString(accountName);
+                userData.seedAccountType = truncateString(accountType);
                 userData.seedAccountOptions = accountOptions;
                 userData.persistSeedData = persist;
             }
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 85b60a0..29e0c35 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -295,6 +295,8 @@
                         .setCredentialShareableWithParent(false)
                         .setMediaSharedWithParent(false)
                         .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
+                        .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
+                        .setHideInSettingsInQuietMode(true)
                         .setCrossProfileIntentFilterAccessControl(
                                 UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
                         .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT));
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index f14941b..46121dc 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.Flags.preventSdkLibApp;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
@@ -403,8 +404,9 @@
 
         try {
             final File baseApk = new File(lite.getBaseApkPath());
+            boolean shouldSkipComponents = lite.isIsSdkLibrary() && preventSdkLibApp();
             final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
-                    lite.getPath(), assetLoader, flags);
+                    lite.getPath(), assetLoader, flags, shouldSkipComponents);
             if (result.isError()) {
                 return input.error(result);
             }
@@ -456,10 +458,11 @@
         final PackageLite lite = liteResult.getResult();
         final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
         try {
+            boolean shouldSkipComponents =  lite.isIsSdkLibrary() && preventSdkLibApp();
             final ParseResult<ParsingPackage> result = parseBaseApk(input,
                     apkFile,
                     apkFile.getCanonicalPath(),
-                    assetLoader, flags);
+                    assetLoader, flags, shouldSkipComponents);
             if (result.isError()) {
                 return input.error(result);
             }
@@ -594,7 +597,8 @@
     }
 
     private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
-            String codePath, SplitAssetLoader assetLoader, int flags) {
+            String codePath, SplitAssetLoader assetLoader, int flags,
+            boolean shouldSkipComponents) {
         final String apkPath = apkFile.getAbsolutePath();
 
         final String volumeUuid = getVolumeUuid(apkPath);
@@ -619,7 +623,7 @@
             final Resources res = new Resources(assets, mDisplayMetrics, null);
 
             ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
-                    parser, flags);
+                    parser, flags, shouldSkipComponents);
             if (result.isError()) {
                 return input.error(result.getErrorCode(),
                         apkPath + " (at " + parser.getPositionDescription() + "): "
@@ -719,11 +723,12 @@
      * @param res     The resources from which to resolve values
      * @param parser  The manifest parser
      * @param flags   Flags how to parse
+     * @param shouldSkipComponents If the package is a sdk-library
      * @return Parsed package or null on error.
      */
     private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
-            String codePath, Resources res, XmlResourceParser parser, int flags)
-            throws XmlPullParserException, IOException {
+            String codePath, Resources res, XmlResourceParser parser, int flags,
+            boolean shouldSkipComponents) throws XmlPullParserException, IOException {
         final String splitName;
         final String pkgName;
 
@@ -751,7 +756,8 @@
             final ParsingPackage pkg = mCallback.startParsingPackage(
                     pkgName, apkPath, codePath, manifestArray, isCoreApp);
             final ParseResult<ParsingPackage> result =
-                    parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
+                    parseBaseApkTags(input, pkg, manifestArray, res, parser, flags,
+                            shouldSkipComponents);
             if (result.isError()) {
                 return result;
             }
@@ -987,10 +993,9 @@
                 return ParsingUtils.unknownTag("<application>", pkg, parser, input);
         }
     }
-
     private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
-            TypedArray sa, Resources res, XmlResourceParser parser, int flags)
-            throws XmlPullParserException, IOException {
+            TypedArray sa, Resources res, XmlResourceParser parser, int flags,
+            boolean shouldSkipComponents) throws XmlPullParserException, IOException {
         ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
         if (sharedUserResult.isError()) {
             return sharedUserResult;
@@ -1027,7 +1032,8 @@
                     }
                 } else {
                     foundApp = true;
-                    result = parseBaseApplication(input, pkg, res, parser, flags);
+                    result = parseBaseApplication(input, pkg, res, parser, flags,
+                            shouldSkipComponents);
                 }
             } else {
                 result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
@@ -1972,8 +1978,8 @@
      * code moves around.
      */
     private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
-            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
-            throws XmlPullParserException, IOException {
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
+            boolean shouldSkipComponents) throws XmlPullParserException, IOException {
         final String pkgName = pkg.getPackageName();
         int targetSdk = pkg.getTargetSdkVersion();
 
@@ -2213,6 +2219,9 @@
                     isActivity = true;
                     // fall-through
                 case "receiver":
+                    if (shouldSkipComponents) {
+                        continue;
+                    }
                     ParseResult<ParsedActivity> activityResult =
                             ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
                                     res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/,
@@ -2232,6 +2241,9 @@
                     result = activityResult;
                     break;
                 case "service":
+                    if (shouldSkipComponents) {
+                        continue;
+                    }
                     ParseResult<ParsedService> serviceResult =
                             ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
                                     flags, sUseRoundIcon, null /*defaultSplitName*/,
@@ -2245,6 +2257,9 @@
                     result = serviceResult;
                     break;
                 case "provider":
+                    if (shouldSkipComponents) {
+                        continue;
+                    }
                     ParseResult<ParsedProvider> providerResult =
                             ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
                                     flags, sUseRoundIcon, null /*defaultSplitName*/,
@@ -2256,6 +2271,9 @@
                     result = providerResult;
                     break;
                 case "activity-alias":
+                    if (shouldSkipComponents) {
+                        continue;
+                    }
                     activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
                             parser, sUseRoundIcon, null /*defaultSplitName*/,
                             input);
@@ -2414,7 +2432,7 @@
     /**
      * For parsing non-MainComponents. Main ones have an order and some special handling which is
      * done directly in {@link #parseBaseApplication(ParseInput, ParsingPackage, Resources,
-     * XmlResourceParser, int)}.
+     * XmlResourceParser, int, boolean)}.
      */
     private ParseResult parseBaseAppChildTag(ParseInput input, String tag, ParsingPackage pkg,
             Resources res, XmlResourceParser parser, int flags)
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index ebc7163..b83421f 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -42,6 +42,7 @@
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.permission.flags.Flags;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
 import android.text.TextUtils;
@@ -75,9 +76,6 @@
     private static final boolean SYSPROP_HOTWORD_DETECTION_SERVICE_REQUIRED =
             SystemProperties.getBoolean("ro.hotword.detection_service_required", false);
 
-    //TODO(b/289087412): import this from the flag value in set up in device config.
-    private static final boolean IS_VOICE_ACTIVATION_OP_ENABLED = false;
-
     @NonNull
     private final Object mLock = new Object();
 
@@ -212,7 +210,7 @@
      * @return the op that should be noted for the voice activations of the app by detected hotword.
      */
     public static int getVoiceActivationOp() {
-        if (IS_VOICE_ACTIVATION_OP_ENABLED) {
+        if (Flags.voiceActivationPermissionApis()) {
             return OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
         }
         return OP_RECORD_AUDIO_HOTWORD;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 097656c..3a6664a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -333,6 +333,11 @@
     static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0;
     static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1;
 
+    // must match: config_shortPressOnSettingsBehavior in config.xml
+    static final int SHORT_PRESS_SETTINGS_NOTHING = 0;
+    static final int SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL = 1;
+    static final int LAST_SHORT_PRESS_SETTINGS_BEHAVIOR = SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL;
+
     static final int PENDING_KEY_NULL = -1;
 
     // Must match: config_shortPressOnStemPrimaryBehavior in config.xml
@@ -611,6 +616,9 @@
     // What we do when the user double-taps on home
     int mDoubleTapOnHomeBehavior;
 
+    // What we do when the user presses on settings
+    int mShortPressOnSettingsBehavior;
+
     // Must match config_primaryShortPressTargetActivity in config.xml
     ComponentName mPrimaryShortPressTargetActivity;
 
@@ -2766,6 +2774,13 @@
         if (mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
             mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
         }
+
+        mShortPressOnSettingsBehavior = res.getInteger(
+                com.android.internal.R.integer.config_shortPressOnSettingsBehavior);
+        if (mShortPressOnSettingsBehavior < SHORT_PRESS_SETTINGS_NOTHING
+                || mShortPressOnSettingsBehavior > LAST_SHORT_PRESS_SETTINGS_BEHAVIOR) {
+            mShortPressOnSettingsBehavior = SHORT_PRESS_SETTINGS_NOTHING;
+        }
     }
 
     private void updateSettings() {
@@ -3632,6 +3647,15 @@
                 Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in"
                         + " interceptKeyBeforeQueueing");
                 return true;
+            case KeyEvent.KEYCODE_SETTINGS:
+                if (mShortPressOnSettingsBehavior == SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL) {
+                    if (!down) {
+                        toggleNotificationPanel();
+                        logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL);
+                    }
+                    return true;
+                }
+                break;
         }
         if (isValidGlobalKey(keyCode)
                 && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
@@ -6272,6 +6296,9 @@
                 pw.print("mLongPressOnPowerBehavior=");
                 pw.println(longPressOnPowerBehaviorToString(mLongPressOnPowerBehavior));
         pw.print(prefix);
+        pw.print("mShortPressOnSettingsBehavior=");
+        pw.println(shortPressOnSettingsBehaviorToString(mShortPressOnSettingsBehavior));
+        pw.print(prefix);
         pw.print("mLongPressOnPowerAssistantTimeoutMs=");
         pw.println(mLongPressOnPowerAssistantTimeoutMs);
         pw.print(prefix);
@@ -6470,6 +6497,17 @@
         }
     }
 
+    private static String shortPressOnSettingsBehaviorToString(int behavior) {
+        switch (behavior) {
+            case SHORT_PRESS_SETTINGS_NOTHING:
+                return "SHORT_PRESS_SETTINGS_NOTHING";
+            case SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL:
+                return "SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL";
+            default:
+                return Integer.toString(behavior);
+        }
+    }
+
     private static String veryLongPressOnPowerBehaviorToString(int behavior) {
         switch (behavior) {
             case VERY_LONG_PRESS_POWER_NOTHING:
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
index c908acd..d5bc912 100644
--- a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
+++ b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
@@ -24,9 +24,10 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.security.keymaster.IKeyAttestationApplicationIdProvider;
-import android.security.keymaster.KeyAttestationApplicationId;
-import android.security.keymaster.KeyAttestationPackageInfo;
+import android.security.keystore.IKeyAttestationApplicationIdProvider;
+import android.security.keystore.KeyAttestationApplicationId;
+import android.security.keystore.KeyAttestationPackageInfo;
+import android.security.keystore.Signature;
 
 /**
  * @hide
@@ -64,14 +65,25 @@
             for (int i = 0; i < packageNames.length; ++i) {
                 PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageNames[i],
                         PackageManager.GET_SIGNATURES, userId);
-                keyAttestationPackageInfos[i] = new KeyAttestationPackageInfo(packageNames[i],
-                        packageInfo.getLongVersionCode(), packageInfo.signatures);
+                KeyAttestationPackageInfo pInfo = new KeyAttestationPackageInfo();
+                pInfo.packageName = new String(packageNames[i]);
+                pInfo.versionCode = packageInfo.getLongVersionCode();
+                pInfo.signatures = new Signature[packageInfo.signatures.length];
+                for (int index = 0; index < packageInfo.signatures.length; index++) {
+                    Signature sign = new Signature();
+                    sign.data = packageInfo.signatures[index].toByteArray();
+                    pInfo.signatures[index] = sign;
+                }
+
+                keyAttestationPackageInfos[i] = pInfo;
             }
         } catch (NameNotFoundException nnfe) {
             throw new RemoteException(nnfe.getMessage());
         } finally {
             Binder.restoreCallingIdentity(token);
         }
-        return new KeyAttestationApplicationId(keyAttestationPackageInfos);
+        KeyAttestationApplicationId attestAppId = new KeyAttestationApplicationId();
+        attestAppId.packageInfos = keyAttestationPackageInfos;
+        return attestAppId;
     }
 }
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
index 3d89afa..becbbf2 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
@@ -25,6 +25,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.HapticFeedbackConstants;
+import android.view.flags.FeatureFlags;
+import android.view.flags.FeatureFlagsImpl;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -54,6 +56,7 @@
     // If present and valid, a vibration here will be used for an effect.
     // Otherwise, the system's default vibration will be used.
     @Nullable private final SparseArray<VibrationEffect> mHapticCustomizations;
+    private final FeatureFlags mViewFeatureFlags;
 
     /** @hide */
     public HapticFeedbackVibrationProvider(Resources res, Vibrator vibrator) {
@@ -62,14 +65,16 @@
 
     /** @hide */
     public HapticFeedbackVibrationProvider(Resources res, VibratorInfo vibratorInfo) {
-        this(res, vibratorInfo, loadHapticCustomizations(res, vibratorInfo));
+        this(res, vibratorInfo, loadHapticCustomizations(res, vibratorInfo),
+                new FeatureFlagsImpl());
     }
 
     /** @hide */
     @VisibleForTesting HapticFeedbackVibrationProvider(
             Resources res,
             VibratorInfo vibratorInfo,
-            @Nullable SparseArray<VibrationEffect> hapticCustomizations) {
+            @Nullable SparseArray<VibrationEffect> hapticCustomizations,
+            FeatureFlags viewFeatureFlags) {
         mVibratorInfo = vibratorInfo;
         mHapticTextHandleEnabled = res.getBoolean(
                 com.android.internal.R.bool.config_enableHapticTextHandle);
@@ -78,6 +83,7 @@
             hapticCustomizations = null;
         }
         mHapticCustomizations = hapticCustomizations;
+        mViewFeatureFlags = viewFeatureFlags;
 
         mSafeModeEnabledVibrationEffect =
                 effectHasCustomization(HapticFeedbackConstants.SAFE_MODE_ENABLED)
@@ -201,12 +207,16 @@
             default:
                 attrs = TOUCH_VIBRATION_ATTRIBUTES;
         }
+
+        int flags = 0;
         if (bypassVibrationIntensitySetting) {
-            attrs = new VibrationAttributes.Builder(attrs)
-                    .setFlags(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)
-                    .build();
+            flags |= VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
         }
-        return attrs;
+        if (shouldBypassInterruptionPolicy(effectId, mViewFeatureFlags)) {
+            flags |= VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
+        }
+
+        return flags == 0 ? attrs : new VibrationAttributes.Builder(attrs).setFlags(flags).build();
     }
 
     /** Dumps relevant state. */
@@ -295,4 +305,19 @@
             return null;
         }
     }
+
+    private static boolean shouldBypassInterruptionPolicy(
+            int effectId, FeatureFlags viewFeatureFlags) {
+        switch (effectId) {
+            case HapticFeedbackConstants.SCROLL_TICK:
+            case HapticFeedbackConstants.SCROLL_ITEM_FOCUS:
+            case HapticFeedbackConstants.SCROLL_LIMIT:
+                // The SCROLL_* constants should bypass interruption filter, so that scroll haptics
+                // can play regardless of focus modes like DND. Guard this behavior by the feature
+                // flag controlling the general scroll feedback APIs.
+                return viewFeatureFlags.scrollFeedbackApi();
+            default:
+                return false;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index ee3d697..45bd152 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -448,6 +448,7 @@
             String reason, IBinder token) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
         try {
+            attrs = fixupVibrationAttributes(attrs, effect);
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.VIBRATE, "vibrate");
             return vibrateInternal(uid, displayId, opPkg, effect, attrs, reason, token);
@@ -457,7 +458,7 @@
     }
 
     HalVibration vibrateWithoutPermissionCheck(int uid, int displayId, String opPkg,
-            @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs,
+            @NonNull CombinedVibration effect, @NonNull VibrationAttributes attrs,
             String reason, IBinder token) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate no perm check, reason = " + reason);
         try {
@@ -468,7 +469,7 @@
     }
 
     private HalVibration vibrateInternal(int uid, int displayId, String opPkg,
-            @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs,
+            @NonNull CombinedVibration effect, @NonNull VibrationAttributes attrs,
             String reason, IBinder token) {
         if (token == null) {
             Slog.e(TAG, "token must not be null");
@@ -478,7 +479,6 @@
         if (!isEffectValid(effect)) {
             return null;
         }
-        attrs = fixupVibrationAttributes(attrs, effect);
         // Create Vibration.Stats as close to the received request as possible, for tracking.
         HalVibration vib = new HalVibration(token, effect,
                 new Vibration.CallerInfo(attrs, uid, displayId, opPkg, reason));
diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
index 10a2b97..05da9df 100644
--- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
+++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
@@ -15,6 +15,9 @@
  */
 package com.android.server.wm;
 
+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 com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -23,6 +26,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -78,7 +82,14 @@
 
     protected final WindowManagerService mService;
     protected final float mHighResSnapshotScale;
-    private final Rect mTmpRect = new Rect();
+
+    /**
+     * The transition change info of the target to capture screenshot. It is only non-null when
+     * capturing a snapshot with a given change info. It must be cleared after
+     * {@link #recordSnapshotInner} is done.
+     */
+    protected Transition.ChangeInfo mCurrentChangeInfo;
+
     /**
      * Flag indicating whether we are running on an Android TV device.
      */
@@ -137,41 +148,35 @@
     protected abstract boolean use16BitFormat();
 
     /**
-     * This is different than {@link #recordSnapshotInner(TYPE, boolean)} because it doesn't store
+     * This is different than {@link #recordSnapshotInner(TYPE)} because it doesn't store
      * the snapshot to the cache and returns the TaskSnapshot immediately.
      *
      * This is only used for testing so the snapshot content can be verified.
      */
-    // TODO(b/264551777): clean up the "snapshotHome" argument
     @VisibleForTesting
-    TaskSnapshot captureSnapshot(TYPE source, boolean snapshotHome) {
+    TaskSnapshot captureSnapshot(TYPE source) {
         final TaskSnapshot snapshot;
-        if (snapshotHome) {
-            snapshot = snapshot(source);
-        } else {
-            switch (getSnapshotMode(source)) {
-                case SNAPSHOT_MODE_NONE:
-                    return null;
-                case SNAPSHOT_MODE_APP_THEME:
-                    snapshot = drawAppThemeSnapshot(source);
-                    break;
-                case SNAPSHOT_MODE_REAL:
-                    snapshot = snapshot(source);
-                    break;
-                default:
-                    snapshot = null;
-                    break;
-            }
+        switch (getSnapshotMode(source)) {
+            case SNAPSHOT_MODE_NONE:
+                return null;
+            case SNAPSHOT_MODE_APP_THEME:
+                snapshot = drawAppThemeSnapshot(source);
+                break;
+            case SNAPSHOT_MODE_REAL:
+                snapshot = snapshot(source);
+                break;
+            default:
+                snapshot = null;
+                break;
         }
         return snapshot;
     }
 
-    final TaskSnapshot recordSnapshotInner(TYPE source, boolean allowSnapshotHome) {
+    final TaskSnapshot recordSnapshotInner(TYPE source) {
         if (shouldDisableSnapshots()) {
             return null;
         }
-        final boolean snapshotHome = allowSnapshotHome && source.isActivityTypeHome();
-        final TaskSnapshot snapshot = captureSnapshot(source, snapshotHome);
+        final TaskSnapshot snapshot = captureSnapshot(source);
         if (snapshot == null) {
             return null;
         }
@@ -189,30 +194,32 @@
 
     @VisibleForTesting
     int getSnapshotMode(TYPE source) {
-        final ActivityRecord topChild = getTopActivity(source);
-        if (!source.isActivityTypeStandardOrUndefined() && !source.isActivityTypeAssistant()) {
+        final int type = source.getActivityType();
+        if (type == ACTIVITY_TYPE_RECENTS || type == ACTIVITY_TYPE_DREAM) {
             return SNAPSHOT_MODE_NONE;
-        } else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
-            return SNAPSHOT_MODE_APP_THEME;
-        } else {
+        }
+        if (type == ACTIVITY_TYPE_HOME) {
             return SNAPSHOT_MODE_REAL;
         }
+        final ActivityRecord topChild = getTopActivity(source);
+        if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
+            return SNAPSHOT_MODE_APP_THEME;
+        }
+        return SNAPSHOT_MODE_REAL;
     }
 
     @Nullable
     TaskSnapshot snapshot(TYPE source) {
-        return snapshot(source, PixelFormat.UNKNOWN);
-    }
-
-    @Nullable
-    TaskSnapshot snapshot(TYPE source, int pixelFormat) {
         TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
-        if (!prepareTaskSnapshot(source, pixelFormat, builder)) {
+        final Rect crop = prepareTaskSnapshot(source, builder);
+        if (crop == null) {
             // Failed some pre-req. Has been logged.
             return null;
         }
-        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
-                createSnapshot(source, builder);
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "createSnapshot");
+        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer = createSnapshot(source,
+                mHighResSnapshotScale, crop, builder);
+        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
         if (screenshotBuffer == null) {
             // Failed to acquire image. Has been logged.
             return null;
@@ -225,37 +232,13 @@
 
     @Nullable
     ScreenCapture.ScreenshotHardwareBuffer createSnapshot(@NonNull TYPE source,
-            TaskSnapshot.Builder builder) {
-        Point taskSize = new Point();
-        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "createSnapshot");
-        final ScreenCapture.ScreenshotHardwareBuffer taskSnapshot = createSnapshot(source,
-                mHighResSnapshotScale, builder.getPixelFormat(), taskSize, builder);
-        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-        builder.setTaskSize(taskSize);
-        return taskSnapshot;
-    }
-
-    @Nullable
-    ScreenCapture.ScreenshotHardwareBuffer createSnapshot(@NonNull TYPE source,
-            float scaleFraction, int pixelFormat, Point outTaskSize, TaskSnapshot.Builder builder) {
+            float scaleFraction, Rect crop, TaskSnapshot.Builder builder) {
         if (source.getSurfaceControl() == null) {
             if (DEBUG_SCREENSHOT) {
                 Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + source);
             }
             return null;
         }
-        mTmpRect.setEmpty();
-        if (source.mTransitionController.inFinishingTransition(source)) {
-            final Transition.ChangeInfo changeInfo = source.mTransitionController
-                    .mFinishingTransition.mChanges.get(source);
-            if (changeInfo != null) {
-                mTmpRect.set(changeInfo.mAbsoluteBounds);
-            }
-        }
-        if (mTmpRect.isEmpty()) {
-            source.getBounds(mTmpRect);
-        }
-        mTmpRect.offsetTo(0, 0);
         SurfaceControl[] excludeLayers;
         final WindowState imeWindow = source.getDisplayContent().mInputMethodWindow;
         // Exclude IME window snapshot when IME isn't proper to attach to app.
@@ -281,12 +264,8 @@
         builder.setHasImeSurface(!excludeIme && imeWindow != null && imeWindow.isVisible());
         final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
                 ScreenCapture.captureLayersExcluding(
-                        source.getSurfaceControl(), mTmpRect, scaleFraction,
-                        pixelFormat, excludeLayers);
-        if (outTaskSize != null) {
-            outTaskSize.x = mTmpRect.width();
-            outTaskSize.y = mTmpRect.height();
-        }
+                        source.getSurfaceControl(), crop, scaleFraction,
+                        builder.getPixelFormat(), excludeLayers);
         final HardwareBuffer buffer = screenshotBuffer == null ? null
                 : screenshotBuffer.getHardwareBuffer();
         if (isInvalidHardwareBuffer(buffer)) {
@@ -305,17 +284,16 @@
      * information from the task and populates the builder.
      *
      * @param source the window to capture
-     * @param pixelFormat the desired pixel format, or {@link PixelFormat#UNKNOWN} to
-     *                    automatically select
      * @param builder the snapshot builder to populate
      *
      * @return true if the state of the task is ok to proceed
      */
     @VisibleForTesting
-    boolean prepareTaskSnapshot(TYPE source, int pixelFormat, TaskSnapshot.Builder builder) {
+    @Nullable
+    Rect prepareTaskSnapshot(TYPE source, TaskSnapshot.Builder builder) {
         final Pair<ActivityRecord, WindowState> result = checkIfReadyToSnapshot(source);
         if (result == null) {
-            return false;
+            return null;
         }
         final ActivityRecord activity = result.first;
         final WindowState mainWindow = result.second;
@@ -329,6 +307,7 @@
         builder.setLetterboxInsets(letterboxInsets);
         final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
         final boolean isShowWallpaper = mainWindow.hasWallpaper();
+        int pixelFormat = builder.getPixelFormat();
         if (pixelFormat == PixelFormat.UNKNOWN) {
             pixelFormat = use16BitFormat() && activity.fillsParent()
                     && !(isWindowTranslucent && isShowWallpaper)
@@ -340,11 +319,29 @@
         builder.setTopActivityComponent(activity.mActivityComponent);
         builder.setPixelFormat(pixelFormat);
         builder.setIsTranslucent(isTranslucent);
-        builder.setOrientation(activity.getTask().getConfiguration().orientation);
-        builder.setRotation(activity.getTask().getDisplayContent().getRotation());
         builder.setWindowingMode(source.getWindowingMode());
         builder.setAppearance(getAppearance(source));
-        return true;
+
+        final Configuration taskConfig = activity.getTask().getConfiguration();
+        final int displayRotation = taskConfig.windowConfiguration.getDisplayRotation();
+        final Rect outCrop = new Rect();
+        final Transition.ChangeInfo changeInfo = mCurrentChangeInfo;
+        if (changeInfo != null && changeInfo.mRotation != displayRotation) {
+            // For example, the source is closing and display rotation changes at the same time.
+            // The snapshot should record the state in previous rotation.
+            outCrop.set(changeInfo.mAbsoluteBounds);
+            builder.setRotation(changeInfo.mRotation);
+            builder.setOrientation(changeInfo.mAbsoluteBounds.height()
+                    >= changeInfo.mAbsoluteBounds.width()
+                    ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE);
+        } else {
+            outCrop.set(taskConfig.windowConfiguration.getBounds());
+            builder.setRotation(displayRotation);
+            builder.setOrientation(taskConfig.orientation);
+        }
+        outCrop.offsetTo(0, 0);
+        builder.setTaskSize(new Point(outCrop.right, outCrop.bottom));
+        return outCrop;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index ed10346..c866dd0 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5367,18 +5367,11 @@
                 // rather than just direct membership.
                 inFinishingTransition = mTransitionController.inFinishingTransition(this);
                 if (!inFinishingTransition && (visible || !mDisplayContent.isSleeping())) {
-                    Slog.e(TAG, "setVisibility=" + visible
-                            + " while transition is not collecting or finishing "
-                            + this + " caller=" + Debug.getCallers(8));
-                    // Force showing the parents because they may be hidden by previous transition.
                     if (visible) {
-                        final Transaction t = getSyncTransaction();
-                        for (WindowContainer<?> p = getParent(); p != null && p != mDisplayContent;
-                                p = p.getParent()) {
-                            if (p.mSurfaceControl != null) {
-                                t.show(p.mSurfaceControl);
-                            }
-                        }
+                        mTransitionController.onVisibleWithoutCollectingTransition(this,
+                                Debug.getCallers(1, 1));
+                    } else {
+                        Slog.w(TAG, "Set invisible without transition " + this);
                     }
                 }
             }
@@ -9269,13 +9262,6 @@
             Slog.w(TAG, errorMessage);
         }
 
-        // Configuration's equality doesn't consider seq so if only seq number changes in resolved
-        // override configuration. Therefore ConfigurationContainer doesn't change merged override
-        // configuration, but it's used to push configuration changes so explicitly update that.
-        if (getMergedOverrideConfiguration().seq != getResolvedOverrideConfiguration().seq) {
-            onMergedOverrideConfigurationChanged();
-        }
-
         // Before PiP animation is done, th windowing mode of the activity is still the previous
         // mode (see RootWindowContainer#moveActivityToPinnedRootTask). So once the windowing mode
         // of activity is changed, it is the signal of the last step to update the PiP states.
diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
index 148bf9b..01b8bf7 100644
--- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java
+++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
@@ -280,7 +280,7 @@
         if (DEBUG) {
             Slog.d(TAG, "ActivitySnapshotController#recordSnapshot " + activity);
         }
-        final TaskSnapshot snapshot = recordSnapshotInner(activity, false /* allowSnapshotHome */);
+        final TaskSnapshot snapshot = recordSnapshotInner(activity);
         if (snapshot != null) {
             final int code = getSystemHashCode(activity);
             addUserSavedFile(code, activity.mUserId, snapshot);
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index c39b266..4a5311b 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -577,7 +577,8 @@
                 .getRootTask(WINDOWING_MODE_UNDEFINED, activityType);
         if (rootTask == null) return false;
         final ActivityRecord r = rootTask.topRunningActivity();
-        if (r == null || r.isVisibleRequested() || !r.attachedToProcess()
+        if (r == null || (r.isVisibleRequested() && rootTask.isTopRootTaskInDisplayArea())
+                || !r.attachedToProcess()
                 || !r.mActivityComponent.equals(intent.getComponent())
                 || !mService.isCallerRecents(r.getUid())
                 // Recents keeps invisible while device is locked.
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 27315bb..7cccf6b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -707,7 +707,7 @@
                 }
             }
 
-            int res;
+            int res = START_CANCELED;
             synchronized (mService.mGlobalLock) {
                 final boolean globalConfigWillChange = mRequest.globalConfig != null
                         && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
@@ -719,22 +719,20 @@
                         + "will change = %b", globalConfigWillChange);
 
                 final long origId = Binder.clearCallingIdentity();
-
-                res = resolveToHeavyWeightSwitcherIfNeeded();
-                if (res != START_SUCCESS) {
-                    return res;
-                }
-
                 try {
+                    res = resolveToHeavyWeightSwitcherIfNeeded();
+                    if (res != START_SUCCESS) {
+                        return res;
+                    }
+
                     res = executeRequest(mRequest);
                 } finally {
+                    Binder.restoreCallingIdentity(origId);
                     mRequest.logMessage.append(" result code=").append(res);
                     Slog.i(TAG, mRequest.logMessage.toString());
                     mRequest.logMessage.setLength(0);
                 }
 
-                Binder.restoreCallingIdentity(origId);
-
                 if (globalConfigWillChange) {
                     // If the caller also wants to switch to a new configuration, do so now.
                     // This allows a clean switch, as we are waiting for the current activity
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a450b4d..0b67321 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3858,11 +3858,9 @@
                     return null;
                 }
                 if (updateCache) {
-                    return mWindowManager.mTaskSnapshotController.recordSnapshot(task,
-                            true /* snapshotHome */);
+                    return mWindowManager.mTaskSnapshotController.recordSnapshot(task);
                 } else {
-                    return mWindowManager.mTaskSnapshotController.captureSnapshot(task,
-                            true /* snapshotHome */);
+                    return mWindowManager.mTaskSnapshotController.captureSnapshot(task);
                 }
             }
         } finally {
@@ -6450,19 +6448,8 @@
                 if (!restarting && hasVisibleActivities) {
                     deferWindowLayout();
                     try {
-                        final Task topTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
-                        if (topTask != null
-                                && topTask.topRunningActivity(true /* focusableOnly */) == null) {
-                            topTask.adjustFocusToNextFocusableTask("handleAppDied");
-                        }
-                        if (!mRootWindowContainer.resumeFocusedTasksTopActivities()) {
-                            // If there was nothing to resume, and we are not already restarting
-                            // this process, but there is a visible activity that is hosted by the
-                            // process...then make sure all visible activities are running, taking
-                            // care of restarting this process.
-                            mRootWindowContainer.ensureActivitiesVisible(null, 0,
-                                    !PRESERVE_WINDOWS);
-                        }
+                        mRootWindowContainer.ensureVisibilityOnVisibleActivityDiedOrCrashed(
+                                "handleAppDied");
                     } finally {
                         continueWindowLayout();
                     }
@@ -6903,7 +6890,18 @@
         @Override
         public int finishTopCrashedActivities(WindowProcessController crashedApp, String reason) {
             synchronized (mGlobalLock) {
-                return mRootWindowContainer.finishTopCrashedActivities(crashedApp, reason);
+                deferWindowLayout();
+                try {
+                    final Task finishedTask = mRootWindowContainer.finishTopCrashedActivities(
+                            crashedApp, reason);
+                    if (finishedTask != null) {
+                        mRootWindowContainer.ensureVisibilityOnVisibleActivityDiedOrCrashed(reason);
+                        return finishedTask.mTaskId;
+                    }
+                    return INVALID_TASK_ID;
+                } finally {
+                    continueWindowLayout();
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 9fd4720..12e1e2c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -47,6 +47,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -1592,6 +1593,9 @@
     }
 
     private void removePinnedRootTaskInSurfaceTransaction(Task rootTask) {
+        rootTask.mTransitionController.requestTransitionIfNeeded(TRANSIT_TO_BACK, 0 /* flags */,
+                rootTask, rootTask.mDisplayContent, null /* remoteTransition */,
+                null /* displayChange */);
         /**
          * Workaround: Force-stop all the activities in the root pinned task before we reparent them
          * to the fullscreen root task.  This is to guarantee that when we are removing a root task,
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index c2885da..4237668 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -163,7 +163,8 @@
 
             if (window == null) {
                 EmbeddedWindowController.EmbeddedWindow embeddedWindow =
-                        wmService.mEmbeddedWindowController.getByFocusToken(focusedWindowToken);
+                        wmService.mEmbeddedWindowController.getByInputTransferToken(
+                                focusedWindowToken);
                 if (embeddedWindow != null) {
                     ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
                             "Current focused window is embeddedWindow. Dispatch KEYCODE_BACK.");
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 2439159..73bcc8d 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -66,29 +66,29 @@
 
 public final class CompatModePackages {
     /**
-     * {@link CompatModePackages#DOWNSCALED_INVERSE} is the gatekeeper of all per-app buffer inverse
-     * downscale changes. Enabling this change will allow the following scaling factors:
-     * {@link CompatModePackages#DOWNSCALE_90}
-     * {@link CompatModePackages#DOWNSCALE_85}
-     * {@link CompatModePackages#DOWNSCALE_80}
-     * {@link CompatModePackages#DOWNSCALE_75}
-     * {@link CompatModePackages#DOWNSCALE_70}
-     * {@link CompatModePackages#DOWNSCALE_65}
-     * {@link CompatModePackages#DOWNSCALE_60}
-     * {@link CompatModePackages#DOWNSCALE_55}
-     * {@link CompatModePackages#DOWNSCALE_50}
-     * {@link CompatModePackages#DOWNSCALE_45}
-     * {@link CompatModePackages#DOWNSCALE_40}
-     * {@link CompatModePackages#DOWNSCALE_35}
-     * {@link CompatModePackages#DOWNSCALE_30}
+     * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> is the gatekeeper of all per-app buffer
+     * inverse downscale changes. Enabling this change will allow the following scaling factors:
+     * <a href="#DOWNSCALE_90">DOWNSCALE_90</a>
+     * <a href="#DOWNSCALE_85">DOWNSCALE_85</a>
+     * <a href="#DOWNSCALE_80">DOWNSCALE_80</a>
+     * <a href="#DOWNSCALE_75">DOWNSCALE_75</a>
+     * <a href="#DOWNSCALE_70">DOWNSCALE_70</a>
+     * <a href="#DOWNSCALE_65">DOWNSCALE_65</a>
+     * <a href="#DOWNSCALE_60">DOWNSCALE_60</a>
+     * <a href="#DOWNSCALE_55">DOWNSCALE_55</a>
+     * <a href="#DOWNSCALE_50">DOWNSCALE_50</a>
+     * <a href="#DOWNSCALE_45">DOWNSCALE_45</a>
+     * <a href="#DOWNSCALE_40">DOWNSCALE_40</a>
+     * <a href="#DOWNSCALE_35">DOWNSCALE_35</a>
+     * <a href="#DOWNSCALE_30">DOWNSCALE_30</a>
      *
-     * If {@link CompatModePackages#DOWNSCALED_INVERSE} is enabled for an app package, then the app
-     * will be forcibly resized to the lowest enabled scaling factor e.g. 1/0.8 if both 1/0.8 and
-     * 1/0.7 (* 100%) were enabled.
+     * If <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> is enabled for an app package, then
+     * the app will be forcibly resized to the lowest enabled scaling factor e.g. 1/0.8 if both
+     * 1/0.8 and 1/0.7 (* 100%) were enabled.
      *
-     * When both {@link CompatModePackages#DOWNSCALED_INVERSE}
-     * and {@link CompatModePackages#DOWNSCALED} are enabled, then
-     * {@link CompatModePackages#DOWNSCALED_INVERSE} takes precedence.
+     * When both <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a>
+     * and <a href="#DOWNSCALED">DOWNSCALED</a> are enabled, then
+     * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> takes precedence.
      */
     @ChangeId
     @Disabled
@@ -96,29 +96,29 @@
     public static final long DOWNSCALED_INVERSE = 273564678L; // This is a Bug ID.
 
     /**
-     * {@link CompatModePackages#DOWNSCALED} is the gatekeeper of all per-app buffer downscaling
+     * <a href="#DOWNSCALED">DOWNSCALED</a> is the gatekeeper of all per-app buffer downscaling
      * changes. Enabling this change will allow the following scaling factors:
-     * {@link CompatModePackages#DOWNSCALE_90}
-     * {@link CompatModePackages#DOWNSCALE_85}
-     * {@link CompatModePackages#DOWNSCALE_80}
-     * {@link CompatModePackages#DOWNSCALE_75}
-     * {@link CompatModePackages#DOWNSCALE_70}
-     * {@link CompatModePackages#DOWNSCALE_65}
-     * {@link CompatModePackages#DOWNSCALE_60}
-     * {@link CompatModePackages#DOWNSCALE_55}
-     * {@link CompatModePackages#DOWNSCALE_50}
-     * {@link CompatModePackages#DOWNSCALE_45}
-     * {@link CompatModePackages#DOWNSCALE_40}
-     * {@link CompatModePackages#DOWNSCALE_35}
-     * {@link CompatModePackages#DOWNSCALE_30}
+     * <a href="#DOWNSCALE_90">DOWNSCALE_90</a>
+     * <a href="#DOWNSCALE_85">DOWNSCALE_85</a>
+     * <a href="#DOWNSCALE_80">DOWNSCALE_80</a>
+     * <a href="#DOWNSCALE_75">DOWNSCALE_75</a>
+     * <a href="#DOWNSCALE_70">DOWNSCALE_70</a>
+     * <a href="#DOWNSCALE_65">DOWNSCALE_65</a>
+     * <a href="#DOWNSCALE_60">DOWNSCALE_60</a>
+     * <a href="#DOWNSCALE_55">DOWNSCALE_55</a>
+     * <a href="#DOWNSCALE_50">DOWNSCALE_50</a>
+     * <a href="#DOWNSCALE_45">DOWNSCALE_45</a>
+     * <a href="#DOWNSCALE_40">DOWNSCALE_40</a>
+     * <a href="#DOWNSCALE_35">DOWNSCALE_35</a>
+     * <a href="#DOWNSCALE_30">DOWNSCALE_30</a>
      *
-     * If {@link CompatModePackages#DOWNSCALED} is enabled for an app package, then the app will be
+     * If <a href="#DOWNSCALED">DOWNSCALED</a> is enabled for an app package, then the app will be
      * forcibly resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were
      * enabled.
      *
-     * When both {@link CompatModePackages#DOWNSCALED_INVERSE}
-     * and {@link CompatModePackages#DOWNSCALED} are enabled, then
-     * {@link CompatModePackages#DOWNSCALED_INVERSE} takes precedence.
+     * When both <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a>
+     * and <a href="#DOWNSCALED">DOWNSCALED</a> are enabled, then
+     * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> takes precedence.
      */
     @ChangeId
     @Disabled
@@ -126,12 +126,13 @@
     public static final long DOWNSCALED = 168419799L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_90} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_90">DOWNSCALE_90</a> for a package will force the app to assume it's
      * running on a display with 90% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 111.11% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 111.11% the vertical and horizontal resolution of
+     * the real display
      */
     @ChangeId
     @Disabled
@@ -139,12 +140,13 @@
     public static final long DOWNSCALE_90 = 182811243L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_85} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_85">DOWNSCALE_85</a> for a package will force the app to assume it's
      * running on a display with 85% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 117.65% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 117.65% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
@@ -152,12 +154,13 @@
     public static final long DOWNSCALE_85 = 189969734L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_80} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_80">DOWNSCALE_80</a> for a package will force the app to assume it's
      * running on a display with 80% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 125% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 125% the vertical and horizontal resolution of the real
+     * display
      */
     @ChangeId
     @Disabled
@@ -165,12 +168,13 @@
     public static final long DOWNSCALE_80 = 176926753L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_75} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_75">DOWNSCALE_75</a> for a package will force the app to assume it's
      * running on a display with 75% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 133.33% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 133.33% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
@@ -178,12 +182,13 @@
     public static final long DOWNSCALE_75 = 189969779L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_70} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_70">DOWNSCALE_70</a> for a package will force the app to assume it's
      * running on a display with 70% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 142.86% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 142.86% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
@@ -191,12 +196,13 @@
     public static final long DOWNSCALE_70 = 176926829L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_65} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_65">DOWNSCALE_65</a> for a package will force the app to assume it's
      * running on a display with 65% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 153.85% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 153.85% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
@@ -204,12 +210,13 @@
     public static final long DOWNSCALE_65 = 189969744L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_60} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_60">DOWNSCALE_60</a> for a package will force the app to assume it's
      * running on a display with 60% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 166.67% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 166.67% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
@@ -217,12 +224,13 @@
     public static final long DOWNSCALE_60 = 176926771L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_55} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_55">DOWNSCALE_55</a> for a package will force the app to assume it's
      * running on a display with 55% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 181.82% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 181.82% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
@@ -230,12 +238,13 @@
     public static final long DOWNSCALE_55 = 189970036L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_50} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_50">DOWNSCALE_50</a> for a package will force the app to assume it's
      * running on a display with 50% vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 200% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 200% the vertical and horizontal resolution of the real
+     * display
      */
     @ChangeId
     @Disabled
@@ -243,12 +252,13 @@
     public static final long DOWNSCALE_50 = 176926741L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_45} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_45">DOWNSCALE_45</a> for a package will force the app to assume it's
      * running on a display with 45% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 222.22% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 222.22% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
@@ -256,12 +266,13 @@
     public static final long DOWNSCALE_45 = 189969782L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_40} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_40">DOWNSCALE_40</a> for a package will force the app to assume it's
      * running on a display with 40% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 250% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 250% the vertical and horizontal resolution of the real
+     * display
      */
     @ChangeId
     @Disabled
@@ -269,12 +280,13 @@
     public static final long DOWNSCALE_40 = 189970038L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_35} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_35">DOWNSCALE_35</a> for a package will force the app to assume it's
      * running on a display with 35% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 285.71% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 285.71% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
@@ -282,12 +294,13 @@
     public static final long DOWNSCALE_35 = 189969749L;
 
     /**
-     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
-     * {@link CompatModePackages#DOWNSCALE_30} for a package will force the app to assume it's
+     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id
+     * <a href="#DOWNSCALE_30">DOWNSCALE_30</a> for a package will force the app to assume it's
      * running on a display with 30% the vertical and horizontal resolution of the real display.
      *
-     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
-     * running on a display with 333.33% the vertical and horizontal resolution of the real display
+     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to
+     * assume it's running on a display with 333.33% the vertical and horizontal resolution of the
+     * real display
      */
     @ChangeId
     @Disabled
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 58d4e82..7947112 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -223,9 +223,9 @@
     }
 
     /**
-     * Update merged override configuration based on corresponding parent's config and notify all
-     * its children. If there is no parent, merged override configuration will set equal to current
-     * override config.
+     * Update merged override configuration based on corresponding parent's config. If there is no
+     * parent, merged override configuration will set equal to current override config. This
+     * doesn't cascade on its own since it's called by {@link #onConfigurationChanged}.
      * @see #mMergedOverrideConfiguration
      */
     void onMergedOverrideConfigurationChanged() {
@@ -240,10 +240,6 @@
         } else {
             mMergedOverrideConfiguration.setTo(mResolvedOverrideConfiguration);
         }
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ConfigurationContainer child = getChildAt(i);
-            child.onMergedOverrideConfigurationChanged();
-        }
     }
 
     /**
@@ -688,8 +684,6 @@
         if (newParent != null) {
             // Update full configuration of this container and all its children.
             onConfigurationChanged(newParent.mFullConfiguration);
-            // Update merged override configuration of this container and all its children.
-            onMergedOverrideConfigurationChanged();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index f81e5d4..df26b10 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -44,6 +44,7 @@
 import android.window.DisplayAreaInfo;
 import android.window.IDisplayAreaOrganizer;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.policy.WindowManagerPolicy;
 
@@ -79,6 +80,12 @@
     private final Configuration mTmpConfiguration = new Configuration();
 
     /**
+     * Prevent duplicate calls to onDisplayAreaAppeared, or early call of onDisplayAreaInfoChanged.
+     */
+    @VisibleForTesting
+    boolean mDisplayAreaAppearedSent;
+
+    /**
      * Whether this {@link DisplayArea} should ignore fixed-orientation request. If {@code true}, it
      * can never specify orientation, but shows the fixed-orientation apps below it in the
      * letterbox; otherwise, it rotates based on the fixed-orientation request.
@@ -582,18 +589,31 @@
         sendDisplayAreaVanished(lastOrganizer);
         if (!skipDisplayAreaAppeared) {
             sendDisplayAreaAppeared();
+        } else if (organizer != null) {
+            // Set as sent since the DisplayAreaAppearedInfo will be sent back when registered.
+            mDisplayAreaAppearedSent = true;
         }
     }
 
+    @VisibleForTesting
     void sendDisplayAreaAppeared() {
-        if (mOrganizer == null) return;
+        if (mOrganizer == null || mDisplayAreaAppearedSent) return;
         mOrganizerController.onDisplayAreaAppeared(mOrganizer, this);
+        mDisplayAreaAppearedSent = true;
     }
 
+    @VisibleForTesting
+    void sendDisplayAreaInfoChanged() {
+        if (mOrganizer == null || !mDisplayAreaAppearedSent) return;
+        mOrganizerController.onDisplayAreaInfoChanged(mOrganizer, this);
+    }
+
+    @VisibleForTesting
     void sendDisplayAreaVanished(IDisplayAreaOrganizer organizer) {
-        if (organizer == null) return;
+        if (organizer == null || !mDisplayAreaAppearedSent) return;
         migrateToNewSurfaceControl(getSyncTransaction());
         mOrganizerController.onDisplayAreaVanished(organizer, this);
+        mDisplayAreaAppearedSent = false;
     }
 
     @Override
@@ -603,7 +623,7 @@
         super.onConfigurationChanged(newParentConfig);
 
         if (mOrganizer != null && getConfiguration().diff(mTmpConfiguration) != 0) {
-            mOrganizerController.onDisplayAreaInfoChanged(mOrganizer, this);
+            sendDisplayAreaInfoChanged();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f6fe9b1..b7b5c2af 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -218,6 +218,7 @@
 import android.view.DisplayInfo;
 import android.view.DisplayShape;
 import android.view.Gravity;
+import android.view.IDecorViewGestureListener;
 import android.view.IDisplayWindowInsetsController;
 import android.view.ISystemGestureExclusionListener;
 import android.view.IWindow;
@@ -471,6 +472,8 @@
 
     private final RemoteCallbackList<ISystemGestureExclusionListener>
             mSystemGestureExclusionListeners = new RemoteCallbackList<>();
+    private final RemoteCallbackList<IDecorViewGestureListener> mDecorViewGestureListener =
+            new RemoteCallbackList<>();
     private final Region mSystemGestureExclusion = new Region();
     private boolean mSystemGestureExclusionWasRestricted = false;
     private final Region mSystemGestureExclusionUnrestricted = new Region();
@@ -5968,6 +5971,27 @@
         mSystemGestureExclusionListeners.unregister(listener);
     }
 
+    void registerDecorViewGestureListener(IDecorViewGestureListener listener) {
+        mDecorViewGestureListener.register(listener);
+    }
+
+    void unregisterDecorViewGestureListener(IDecorViewGestureListener listener) {
+        mDecorViewGestureListener.unregister(listener);
+    }
+
+    void updateDecorViewGestureIntercepted(IBinder token, boolean intercepted) {
+        for (int i = mDecorViewGestureListener.beginBroadcast() - 1; i >= 0; --i) {
+            try {
+                mDecorViewGestureListener
+                        .getBroadcastItem(i)
+                        .onInterceptionChanged(token, intercepted);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to notify DecorViewGestureListener", e);
+            }
+        }
+        mDecorViewGestureListener.finishBroadcast();
+    }
+
     void updateKeepClearAreas() {
         final Set<Rect> restrictedKeepClearAreas = new ArraySet<>();
         final Set<Rect> unrestrictedKeepClearAreas = new ArraySet<>();
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 0f1a105..7af4aad 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -48,7 +48,6 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
-import android.os.InputConfig;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -186,6 +185,10 @@
         // Crop the input surface to the display size.
         mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
 
+        // Make trusted overlay to not block any touches while D&D ongoing and allowing
+        // touches to pass through to windows underneath. This allows user to interact with the
+        // UI to navigate while dragging.
+        h.setTrustedOverlay(mTransaction, mInputSurface, true);
         mTransaction.show(mInputSurface)
                 .setInputWindowInfo(mInputSurface, h)
                 .setLayer(mInputSurface, Integer.MAX_VALUE)
@@ -377,11 +380,6 @@
             mDragWindowHandle.ownerUid = MY_UID;
             mDragWindowHandle.scaleFactor = 1.0f;
 
-            // InputConfig.TRUSTED_OVERLAY: To not block any touches while D&D ongoing and allowing
-            // touches to pass through to windows underneath. This allows user to interact with the
-            // UI to navigate while dragging.
-            mDragWindowHandle.inputConfig = InputConfig.TRUSTED_OVERLAY;
-
             // The drag window cannot receive new touches.
             mDragWindowHandle.touchableRegion.setEmpty();
 
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index c9bae12..275396f 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -45,8 +45,8 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "EmbeddedWindowController" : TAG_WM;
     /* maps input token to an embedded window */
     private ArrayMap<IBinder /*input token */, EmbeddedWindow> mWindows = new ArrayMap<>();
-    private ArrayMap<IBinder /*focus grant token */, EmbeddedWindow> mWindowsByFocusToken =
-        new ArrayMap<>();
+    private ArrayMap<IBinder /*input transfer token */, EmbeddedWindow>
+            mWindowsByInputTransferToken = new ArrayMap<>();
     private ArrayMap<IBinder /*window token*/, EmbeddedWindow> mWindowsByWindowToken =
         new ArrayMap<>();
     private final Object mGlobalLock;
@@ -67,14 +67,14 @@
     void add(IBinder inputToken, EmbeddedWindow window) {
         try {
             mWindows.put(inputToken, window);
-            final IBinder focusToken = window.getFocusGrantToken();
-            mWindowsByFocusToken.put(focusToken, window);
+            final IBinder inputTransferToken = window.getInputTransferToken();
+            mWindowsByInputTransferToken.put(inputTransferToken, window);
             mWindowsByWindowToken.put(window.getWindowToken(), window);
             updateProcessController(window);
             window.mClient.asBinder().linkToDeath(()-> {
                 synchronized (mGlobalLock) {
                     mWindows.remove(inputToken);
-                    mWindowsByFocusToken.remove(focusToken);
+                    mWindowsByInputTransferToken.remove(inputTransferToken);
                 }
             }, 0);
         } catch (RemoteException e) {
@@ -105,7 +105,7 @@
             EmbeddedWindow ew = mWindows.valueAt(i);
             if (ew.mClient.asBinder() == client.asBinder()) {
                 mWindows.removeAt(i).onRemoved();
-                mWindowsByFocusToken.remove(ew.getFocusGrantToken());
+                mWindowsByInputTransferToken.remove(ew.getInputTransferToken());
                 mWindowsByWindowToken.remove(ew.getWindowToken());
                 return;
             }
@@ -117,7 +117,7 @@
             EmbeddedWindow ew = mWindows.valueAt(i);
             if (ew.mHostWindowState == host) {
                 mWindows.removeAt(i).onRemoved();
-                mWindowsByFocusToken.remove(ew.getFocusGrantToken());
+                mWindowsByInputTransferToken.remove(ew.getInputTransferToken());
                 mWindowsByWindowToken.remove(ew.getWindowToken());
             }
         }
@@ -127,8 +127,8 @@
         return mWindows.get(inputToken);
     }
 
-    EmbeddedWindow getByFocusToken(IBinder focusGrantToken) {
-        return mWindowsByFocusToken.get(focusGrantToken);
+    EmbeddedWindow getByInputTransferToken(IBinder inputTransferToken) {
+        return mWindowsByInputTransferToken.get(inputTransferToken);
     }
 
     EmbeddedWindow getByWindowToken(IBinder windowToken) {
@@ -153,7 +153,7 @@
          * to request focus transfer to the embedded. This is not the input token since we don't
          * want to give clients access to each others input token.
          */
-        private final IBinder mFocusGrantToken;
+        private final IBinder mInputTransferToken;
 
         private boolean mIsFocusable;
 
@@ -171,7 +171,7 @@
          */
         EmbeddedWindow(Session session, WindowManagerService service, IWindow clientToken,
                        WindowState hostWindowState, int ownerUid, int ownerPid, int windowType,
-                       int displayId, IBinder focusGrantToken, String inputHandleName,
+                       int displayId, IBinder inputTransferToken, String inputHandleName,
                        boolean isFocusable) {
             mSession = session;
             mWmService = service;
@@ -183,7 +183,7 @@
             mOwnerPid = ownerPid;
             mWindowType = windowType;
             mDisplayId = displayId;
-            mFocusGrantToken = focusGrantToken;
+            mInputTransferToken = inputTransferToken;
             final String hostWindowName =
                     (mHostWindowState != null) ? "-" + mHostWindowState.getWindowTag().toString()
                             : "";
@@ -260,8 +260,8 @@
             return mOwnerUid;
         }
 
-        IBinder getFocusGrantToken() {
-            return mFocusGrantToken;
+        IBinder getInputTransferToken() {
+            return mInputTransferToken;
         }
 
         IBinder getInputChannelToken() {
@@ -290,7 +290,7 @@
                     // Use null session since this is being granted by system server and doesn't
                     // require the host session to be passed in
                     mWmService.grantEmbeddedWindowFocus(null, mHostWindowState.mClient,
-                            mFocusGrantToken, grantFocus);
+                            mInputTransferToken, grantFocus);
                     if (grantFocus) {
                         // If granting focus to the embedded when tapped, we need to ensure the host
                         // gains focus as well or the transfer won't take effect since it requires
@@ -298,7 +298,7 @@
                         mHostWindowState.handleTapOutsideFocusInsideSelf();
                     }
                 } else {
-                    mWmService.grantEmbeddedWindowFocus(mSession, mFocusGrantToken, grantFocus);
+                    mWmService.grantEmbeddedWindowFocus(mSession, mInputTransferToken, grantFocus);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 39622c1..c21930d 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -74,7 +74,7 @@
         mWindowHandle.ownerPid = WindowManagerService.MY_PID;
         mWindowHandle.ownerUid = WindowManagerService.MY_UID;
         mWindowHandle.scaleFactor = 1.0f;
-        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY;
+        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
 
         mInputSurface = mService.makeSurfaceBuilder(
                         mService.mRoot.getDisplayContent(displayId).getSession())
@@ -129,12 +129,14 @@
 
     void show(SurfaceControl.Transaction t, WindowContainer w) {
         t.show(mInputSurface);
+        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1);
     }
 
     void show(SurfaceControl.Transaction t, int layer) {
         t.show(mInputSurface);
+        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
         t.setInputWindowInfo(mInputSurface, mWindowHandle);
         t.setLayer(mInputSurface, layer);
     }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 825d38b..af307ec3 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -675,6 +675,11 @@
                     w.getKeyInterceptionInfo());
 
             if (w.mWinAnimator.hasSurface()) {
+                // Update trusted overlay changes here because they are tied to input info. Input
+                // changes can be updated even if surfaces aren't.
+                inputWindowHandle.setTrustedOverlay(mInputTransaction,
+                        w.mWinAnimator.mSurfaceController.mSurfaceControl,
+                        w.isWindowTrustedOverlay());
                 populateInputWindowHandle(inputWindowHandle, w);
                 setInputWindowInfoIfNeeded(mInputTransaction,
                         w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
@@ -732,7 +737,7 @@
                 new InputWindowHandle(null /* inputApplicationHandle */, displayId));
         inputWindowHandle.setName(name);
         inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY);
-        inputWindowHandle.setTrustedOverlay(true);
+        inputWindowHandle.setTrustedOverlay(t, sc, true);
         populateOverlayInputInfo(inputWindowHandle);
         setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);
     }
diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
index 64b7a60..90d81bd 100644
--- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -195,6 +195,11 @@
         mChanged = true;
     }
 
+    void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc,
+            boolean trustedOverlay) {
+        mHandle.setTrustedOverlay(t, sc, trustedOverlay);
+    }
+
     void setOwnerPid(int pid) {
         if (mHandle.ownerPid == pid) {
             return;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index def32a1..82d4b90 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -62,6 +62,7 @@
 import android.window.TaskSnapshot;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.LocalServices;
 import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -244,7 +245,8 @@
         }
 
         @Override
-        public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) {
+        public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint,
+                IResultReceiver finishCb) {
             ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
                     "finish(%b): mCanceled=%b", moveHomeToTop, mCanceled);
             final long token = Binder.clearCallingIdentity();
@@ -257,6 +259,13 @@
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
+            if (finishCb != null) {
+                try {
+                    finishCb.send(0, new Bundle());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to report animation finished", e);
+                }
+            }
         }
 
         @Override
@@ -901,7 +910,8 @@
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
             final Task task = adapter.mTask;
-            snapshotController.recordSnapshot(task, false /* allowSnapshotHome */);
+            if (task.isActivityTypeHome()) continue;
+            snapshotController.recordSnapshot(task);
             final TaskSnapshot snapshot = snapshotController.getSnapshot(task.mTaskId, task.mUserId,
                     false /* restoreFromDisk */, false /* isLowResolution */);
             if (snapshot != null) {
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index 99831d3..23c135a 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -19,6 +19,8 @@
 import static android.hardware.display.DisplayManager.SWITCHING_TYPE_NONE;
 import static android.hardware.display.DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY;
 
+import static com.android.window.flags.Flags.explicitRefreshRateHints;
+
 import android.hardware.display.DisplayManager;
 import android.view.Display;
 import android.view.Display.Mode;
@@ -137,7 +139,7 @@
         // to run in default refresh rate. But if the display size of default mode is different
         // from the using preferred mode, then still keep the preferred mode to avoid disturbing
         // the animation.
-        if (w.isAnimationRunningSelfOrParent()) {
+        if (!explicitRefreshRateHints() && w.isAnimationRunningSelfOrParent()) {
             Display.Mode preferredMode = null;
             for (Display.Mode mode : mDisplayInfo.supportedModes) {
                 if (preferredDisplayModeId == mode.getModeId()) {
@@ -251,7 +253,7 @@
 
         // If app is animating, it's not able to control refresh rate because we want the animation
         // to run in default refresh rate.
-        if (w.isAnimationRunningSelfOrParent()) {
+        if (!explicitRefreshRateHints() && w.isAnimationRunningSelfOrParent()) {
             return w.mFrameRateVote.reset();
         }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 5533759..cf6a1fe 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -60,6 +60,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
 import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH;
+import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;
 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
@@ -2017,6 +2018,13 @@
     void moveActivityToPinnedRootTask(@NonNull ActivityRecord r,
             @Nullable ActivityRecord launchIntoPipHostActivity, String reason,
             @Nullable Transition transition) {
+        moveActivityToPinnedRootTask(r, launchIntoPipHostActivity, reason, transition,
+                null /* bounds */);
+    }
+
+    void moveActivityToPinnedRootTask(@NonNull ActivityRecord r,
+            @Nullable ActivityRecord launchIntoPipHostActivity, String reason,
+            @Nullable Transition transition, @Nullable Rect bounds) {
         final TaskDisplayArea taskDisplayArea = r.getDisplayArea();
         final Task task = r.getTask();
         final Task rootTask;
@@ -2053,7 +2061,9 @@
             // Defer the windowing mode change until after the transition to prevent the activity
             // from doing work and changing the activity visuals while animating
             // TODO(task-org): Figure-out more structured way to do this long term.
-            r.setWindowingMode(r.getWindowingMode());
+            if (!isPip2ExperimentEnabled()) {
+                r.setWindowingMode(r.getWindowingMode());
+            }
 
             final TaskFragment organizedTf = r.getOrganizedTaskFragment();
             final boolean singleActivity = task.getNonFinishingActivityCount() == 1;
@@ -2169,21 +2179,27 @@
             // TODO(remove-legacy-transit): Move this to the `singleActivity` case when removing
             //                              legacy transit.
             rootTask.setWindowingMode(WINDOWING_MODE_PINNED);
+            if (isPip2ExperimentEnabled() && bounds != null) {
+                // set the final pip bounds in advance if pip2 is enabled
+                rootTask.setBounds(bounds);
+            }
+
             // Set the launch bounds for launch-into-pip Activity on the root task.
             if (r.getOptions() != null && r.getOptions().isLaunchIntoPip()) {
                 // Record the snapshot now, it will be later fetched for content-pip animation.
                 // We do this early in the process to make sure the right snapshot is used for
                 // entering content-pip animation.
-                mWindowManager.mTaskSnapshotController.recordSnapshot(
-                        task, false /* allowSnapshotHome */);
+                mWindowManager.mTaskSnapshotController.recordSnapshot(task);
                 rootTask.setBounds(r.pictureInPictureArgs.getSourceRectHint());
             }
             rootTask.setDeferTaskAppear(false);
 
-            // After setting this, it is not expected to change activity configuration until the
-            // transition animation is finished. So the activity can keep consistent appearance
-            // when animating.
-            r.mWaitForEnteringPinnedMode = true;
+            if (!isPip2ExperimentEnabled()) {
+                // After setting this, it is not expected to change activity configuration until the
+                // transition animation is finished. So the activity can keep consistent appearance
+                // when animating.
+                r.mWaitForEnteringPinnedMode = true;
+            }
             // Reset the state that indicates it can enter PiP while pausing after we've moved it
             // to the root pinned task
             r.supportsEnterPipOnTaskSwitch = false;
@@ -2198,7 +2214,9 @@
         } finally {
             mService.continueWindowLayout();
             try {
-                ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+                if (!isPip2ExperimentEnabled()) {
+                    ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+                }
             } finally {
                 transitionController.continueTransitionReady();
             }
@@ -2214,7 +2232,9 @@
             newTransition.setReady(rootTask, true /* ready */);
         }
 
-        resumeFocusedTasksTopActivities();
+        if (!isPip2ExperimentEnabled()) {
+            resumeFocusedTasksTopActivities();
+        }
 
         notifyActivityPipModeChanged(r.getTask(), r);
     }
@@ -2299,19 +2319,36 @@
      *
      * @param app    The app that crashed.
      * @param reason Reason to perform this action.
-     * @return The task id that was finished in this root task, or INVALID_TASK_ID if none was
-     * finished.
+     * @return The finished task which was on top or visible, otherwise {@code null} if the crashed
+     *         app doesn't have activity in visible task.
      */
-    int finishTopCrashedActivities(WindowProcessController app, String reason) {
+    @Nullable
+    Task finishTopCrashedActivities(WindowProcessController app, String reason) {
         Task focusedRootTask = getTopDisplayFocusedRootTask();
         final Task[] finishedTask = new Task[1];
         forAllRootTasks(rootTask -> {
+            final boolean recordTopOrVisible = finishedTask[0] == null
+                    && (focusedRootTask == rootTask || rootTask.isVisibleRequested());
             final Task t = rootTask.finishTopCrashedActivityLocked(app, reason);
-            if (rootTask == focusedRootTask || finishedTask[0] == null) {
+            if (recordTopOrVisible) {
                 finishedTask[0] = t;
             }
         });
-        return finishedTask[0] != null ? finishedTask[0].mTaskId : INVALID_TASK_ID;
+        return finishedTask[0];
+    }
+
+    void ensureVisibilityOnVisibleActivityDiedOrCrashed(String reason) {
+        final Task topTask = getTopDisplayFocusedRootTask();
+        if (topTask != null && topTask.topRunningActivity(true /* focusableOnly */) == null) {
+            // Move the next focusable task to front.
+            topTask.adjustFocusToNextFocusableTask(reason);
+        }
+        if (!resumeFocusedTasksTopActivities()) {
+            // It may be nothing to resume because there are pausing activities or all the top
+            // activities are resumed. Then it still needs to make sure all visible activities are
+            // running in case the tasks were reordered or there are non-top visible activities.
+            ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS);
+        }
     }
 
     boolean resumeFocusedTasksTopActivities() {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index bbe44c5..3775ccd 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -560,6 +560,16 @@
     }
 
     @Override
+    public void reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mService.reportDecorViewGestureChanged(this, window, intercepted);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public void reportKeepClearAreasChanged(IWindow window, List<Rect> restricted,
             List<Rect> unrestricted) {
         if (!mSetsUnrestrictedKeepClearAreas && !unrestricted.isEmpty()) {
@@ -884,8 +894,8 @@
     @Override
     public void grantInputChannel(int displayId, SurfaceControl surface,
             IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type,
-            int inputFeatures, IBinder windowToken, IBinder focusGrantToken, String inputHandleName,
-            InputChannel outInputChannel) {
+            int inputFeatures, IBinder windowToken, IBinder inputTransferToken,
+            String inputHandleName, InputChannel outInputChannel) {
         if (hostInputToken == null && !mCanAddInternalSystemWindow) {
             // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
             // embedded windows without providing a host window input token
@@ -896,7 +906,7 @@
         try {
             mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken,
                     flags, mCanAddInternalSystemWindow ? privateFlags : 0,
-                    type, inputFeatures, windowToken, focusGrantToken, inputHandleName,
+                    type, inputFeatures, windowToken, inputTransferToken, inputHandleName,
                     outInputChannel);
         } finally {
             Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/wm/SnapshotController.java b/services/core/java/com/android/server/wm/SnapshotController.java
index 37f9730..2e7ff7a 100644
--- a/services/core/java/com/android/server/wm/SnapshotController.java
+++ b/services/core/java/com/android/server/wm/SnapshotController.java
@@ -83,9 +83,10 @@
             Transition.ChangeInfo info = changeInfos.get(i);
             // Intentionally skip record snapshot for changes originated from PiP.
             if (info.mWindowingMode == WINDOWING_MODE_PINNED) continue;
-            if (info.mContainer.asTask() != null && !info.mContainer.isVisibleRequested()) {
-                mTaskSnapshotController.recordSnapshot(info.mContainer.asTask(),
-                        false /* allowSnapshotHome */);
+            if (info.mContainer.isActivityTypeHome()) continue;
+            final Task task = info.mContainer.asTask();
+            if (task != null && !task.isVisibleRequested()) {
+                mTaskSnapshotController.recordSnapshot(task, info);
             }
             // Won't need to capture activity snapshot in close transition.
             if (isTransitionClose) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 4eb4290..2b12e74 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -118,6 +118,7 @@
         mTmpTasks.clear();
         for (int i = closingApps.size() - 1; i >= 0; i--) {
             final ActivityRecord activity = closingApps.valueAt(i);
+            if (activity.isActivityTypeHome()) continue;
             final Task task = activity.getTask();
             if (task == null) continue;
 
@@ -144,25 +145,34 @@
     }
 
     void snapshotTasks(ArraySet<Task> tasks) {
-        snapshotTasks(tasks, false /* allowSnapshotHome */);
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            recordSnapshot(tasks.valueAt(i));
+        }
     }
 
-    TaskSnapshot recordSnapshot(Task task, boolean allowSnapshotHome) {
-        final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
-        final TaskSnapshot snapshot = recordSnapshotInner(task, allowSnapshotHome);
-        if (!snapshotHome && snapshot != null) {
+    /**
+     * The attributes of task snapshot are based on task configuration. But sometimes the
+     * configuration may have been changed during a transition, so supply the ChangeInfo that
+     * stored the previous appearance of the closing task.
+     */
+    void recordSnapshot(Task task, Transition.ChangeInfo changeInfo) {
+        mCurrentChangeInfo = changeInfo;
+        try {
+            recordSnapshot(task);
+        } finally {
+            mCurrentChangeInfo = null;
+        }
+    }
+
+    TaskSnapshot recordSnapshot(Task task) {
+        final TaskSnapshot snapshot = recordSnapshotInner(task);
+        if (snapshot != null && !task.isActivityTypeHome()) {
             mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
             task.onSnapshotChanged(snapshot);
         }
         return snapshot;
     }
 
-    private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
-        for (int i = tasks.size() - 1; i >= 0; i--) {
-            recordSnapshot(tasks.valueAt(i), allowSnapshotHome);
-        }
-    }
-
     /**
      * Retrieves a snapshot. If {@param restoreFromDisk} equals {@code true}, DO NOT HOLD THE WINDOW
      * MANAGER LOCK WHEN CALLING THIS METHOD!
@@ -320,19 +330,22 @@
         if (displayContent == null) {
             return;
         }
+        // Allow taking snapshot of home when turning screen off to reduce the delay of waking from
+        // secure lock to home.
+        final boolean allowSnapshotHome = displayId == Display.DEFAULT_DISPLAY
+                && mService.mPolicy.isKeyguardSecure(mService.mCurrentUserId);
         mTmpTasks.clear();
-        displayContent.forAllTasks(task -> {
+        displayContent.forAllLeafTasks(task -> {
+            if (!allowSnapshotHome && task.isActivityTypeHome()) {
+                return;
+            }
             // Since RecentsAnimation will handle task snapshot while switching apps with the best
             // capture timing (e.g. IME window capture), No need additional task capture while task
             // is controlled by RecentsAnimation.
             if (task.isVisible() && !isAnimatingByRecents(task)) {
                 mTmpTasks.add(task);
             }
-        });
-        // Allow taking snapshot of home when turning screen off to reduce the delay of waking from
-        // secure lock to home.
-        final boolean allowSnapshotHome = displayId == Display.DEFAULT_DISPLAY
-                && mService.mPolicy.isKeyguardSecure(mService.mCurrentUserId);
-        snapshotTasks(mTmpTasks, allowSnapshotHome);
+        }, true /* traverseTopToBottom */);
+        snapshotTasks(mTmpTasks);
     }
 }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 774be9e..f3fb7c4 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -372,8 +372,7 @@
             parent.forAllTasks(t -> {
                 // Skip transient-launch task
                 if (t == transientRootTask) return false;
-                if (t.isVisibleRequested() && !t.isAlwaysOnTop()
-                        && !t.getWindowConfiguration().tasksAreFloating()) {
+                if (t.isVisibleRequested() && !t.isAlwaysOnTop()) {
                     if (t.isRootTask()) {
                         mTransientHideTasks.add(t);
                     }
@@ -704,6 +703,7 @@
         if (dc == null || mTargetDisplays.contains(dc)) return;
         mTargetDisplays.add(dc);
         addOnTopTasks(dc, mOnTopTasksStart);
+        mController.startPerfHintForDisplay(dc.mDisplayId);
     }
 
     /**
@@ -1197,7 +1197,8 @@
                         ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                                 "  Commit activity becoming invisible: %s", ar);
                         final SnapshotController snapController = mController.mSnapshotController;
-                        if (mTransientLaunches != null && !task.isVisibleRequested()) {
+                        if (mTransientLaunches != null && !task.isVisibleRequested()
+                                && !task.isActivityTypeHome()) {
                             final long startTimeNs = mLogger.mSendTimeNs;
                             final long lastSnapshotTimeNs = snapController.mTaskSnapshotController
                                     .getSnapshotCaptureTime(task.mTaskId);
@@ -1205,8 +1206,7 @@
                             // transition only if a snapshot was not already captured by request
                             // during the transition
                             if (lastSnapshotTimeNs < startTimeNs) {
-                                snapController.mTaskSnapshotController
-                                        .recordSnapshot(task, false /* allowSnapshotHome */);
+                                snapController.mTaskSnapshotController.recordSnapshot(task);
                             } else {
                                 ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                                         "  Skipping post-transition snapshot for task %d",
@@ -1392,7 +1392,6 @@
             dc.handleCompleteDeferredRemoval();
         }
         validateKeyguardOcclusion();
-        validateVisibility();
 
         mState = STATE_FINISHED;
         // Rotation change may be deferred while there is a display change transition, so check
@@ -2767,29 +2766,6 @@
         }
     }
 
-    private void validateVisibility() {
-        for (int i = mTargets.size() - 1; i >= 0; --i) {
-            if (reduceMode(mTargets.get(i).mReadyMode) != TRANSIT_CLOSE) {
-                return;
-            }
-        }
-        // All modes are CLOSE. The surfaces may be hidden by the animation unexpectedly.
-        // If the window container should be visible, then recover it.
-        mController.mStateValidators.add(() -> {
-            for (int i = mTargets.size() - 1; i >= 0; --i) {
-                final ChangeInfo change = mTargets.get(i);
-                if (!change.mContainer.isVisibleRequested()
-                        || change.mContainer.mSurfaceControl == null) {
-                    continue;
-                }
-                Slog.e(TAG, "Force show for visible " + change.mContainer
-                        + " which may be hidden by transition unexpectedly");
-                change.mContainer.getSyncTransaction().show(change.mContainer.mSurfaceControl);
-                change.mContainer.scheduleAnimation();
-            }
-        });
-    }
-
     /**
      * Returns {@code true} if the transition and the corresponding transaction should be applied
      * on display thread. Currently, this only checks for display rotation change because the order
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 7109137..f509463 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -22,8 +22,10 @@
 import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
 import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.window.SystemPerformanceHinter.HINT_SF;
 
 import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
+import static com.android.window.flags.Flags.explicitRefreshRateHints;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -39,6 +41,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -48,6 +51,8 @@
 import android.window.ITransitionMetricsReporter;
 import android.window.ITransitionPlayer;
 import android.window.RemoteTransition;
+import android.window.SystemPerformanceHinter;
+import android.window.SystemPerformanceHinter.HighPerfSession;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
@@ -125,6 +130,8 @@
     SnapshotController mSnapshotController;
     TransitionTracer mTransitionTracer;
 
+    private SystemPerformanceHinter mSystemPerformanceHinter;
+
     private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners =
             new ArrayList<>();
 
@@ -176,6 +183,24 @@
 
     private final IBinder.DeathRecipient mTransitionPlayerDeath;
 
+    /**
+     * Tracks active perf sessions that boost frame rate and hint sf to increase its
+     * estimated work duration.
+     */
+    private final ArraySet<HighPerfSession> mHighPerfSessions = new ArraySet<>();
+
+
+    /**
+     * Starts a perf hint session which will boost the refresh rate for the display and change
+     * sf duration to handle larger workloads.
+     */
+    void startPerfHintForDisplay(int displayId) {
+        if (explicitRefreshRateHints()) {
+            mHighPerfSessions.add(mSystemPerformanceHinter.startSession(HINT_SF, displayId,
+                    "Transition collected"));
+        }
+    }
+
     static class QueuedTransition {
         final Transition mTransition;
         final OnStartCollect mOnStartCollect;
@@ -255,6 +280,12 @@
         mIsWaitingForDisplayEnabled = !wms.mDisplayEnabled;
         registerLegacyListener(wms.mActivityManagerAppTransitionNotifier);
         setSyncEngine(wms.mSyncEngine);
+        setSystemPerformanceHinter(wms.mSystemPerformanceHinter);
+    }
+
+    @VisibleForTesting
+    void setSystemPerformanceHinter(SystemPerformanceHinter hinter) {
+        mSystemPerformanceHinter = hinter;
     }
 
     @VisibleForTesting
@@ -721,6 +752,7 @@
             // set the pip task in the request if provided
             if (mCollectingTransition.getPipActivity() != null) {
                 pipTaskInfo = mCollectingTransition.getPipActivity().getTask().getTaskInfo();
+                mCollectingTransition.setPipActivity(null);
             }
 
             final TransitionRequestInfo request = new TransitionRequestInfo(transition.mType,
@@ -959,6 +991,36 @@
         mValidateDisplayVis.clear();
     }
 
+    void onVisibleWithoutCollectingTransition(WindowContainer<?> wc, String caller) {
+        final boolean isPlaying = !mPlayingTransitions.isEmpty();
+        Slog.e(TAG, "Set visible without transition " + wc + " playing=" + isPlaying
+                + " caller=" + caller);
+        if (!isPlaying) {
+            enforceSurfaceVisible(wc);
+            return;
+        }
+        // Update surface visibility after the playing transitions are finished, so the last
+        // visibility won't be replaced by the finish transaction of transition.
+        mStateValidators.add(() -> {
+            if (wc.isVisibleRequested()) {
+                enforceSurfaceVisible(wc);
+            }
+        });
+    }
+
+    private void enforceSurfaceVisible(WindowContainer<?> wc) {
+        if (wc.mSurfaceControl == null) return;
+        wc.getSyncTransaction().show(wc.mSurfaceControl);
+        // Force showing the parents because they may be hidden by previous transition.
+        for (WindowContainer<?> p = wc.getParent(); p != null && p != wc.mDisplayContent;
+                p = p.getParent()) {
+            if (p.mSurfaceControl != null) {
+                p.getSyncTransaction().show(p.mSurfaceControl);
+            }
+        }
+        wc.scheduleAnimation();
+    }
+
     /**
      * Called when the transition has a complete set of participants for its operation. In other
      * words, it is when the transition is "ready" but is still waiting for participants to draw.
@@ -1163,18 +1225,27 @@
         final boolean animatingState = !mPlayingTransitions.isEmpty()
                     || (mCollectingTransition != null && mCollectingTransition.isStarted());
         if (animatingState && !mAnimatingState) {
-            t.setEarlyWakeupStart();
+            if (!explicitRefreshRateHints()) {
+                t.setEarlyWakeupStart();
+            }
             // Usually transitions put quite a load onto the system already (with all the things
             // happening in app), so pause task snapshot persisting to not increase the load.
             mSnapshotController.setPause(true);
             mAnimatingState = true;
             Transition.asyncTraceBegin("animating", 0x41bfaf1 /* hashcode of TAG */);
         } else if (!animatingState && mAnimatingState) {
-            t.setEarlyWakeupEnd();
+            if (!explicitRefreshRateHints()) {
+                t.setEarlyWakeupEnd();
+            }
             mAtm.mWindowManager.scheduleAnimationLocked();
             mSnapshotController.setPause(false);
             mAnimatingState = false;
             Transition.asyncTraceEnd(0x41bfaf1 /* hashcode of TAG */);
+            // We close all perf sessions here when all transitions finish. The sessions are created
+            // when we collect transitions because we have access to the display id.
+            for (HighPerfSession perfSession : mHighPerfSessions) {
+                perfSession.close();
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 7e5dabb..674ff48 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -85,13 +85,8 @@
     // to another, and this is the previous wallpaper target.
     private WindowState mPrevWallpaperTarget = null;
 
-    private float mLastWallpaperX = -1;
-    private float mLastWallpaperY = -1;
-    private float mLastWallpaperXStep = -1;
-    private float mLastWallpaperYStep = -1;
     private float mLastWallpaperZoomOut = 0;
-    private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
-    private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
+
     // Whether COMMAND_FREEZE was dispatched.
     private boolean mLastFrozen = false;
 
@@ -116,8 +111,6 @@
     private static final int WALLPAPER_DRAW_TIMEOUT = 2;
     private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
 
-    private boolean mShouldUpdateZoom;
-
     @Nullable private Point mLargestDisplaySize = null;
 
     private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
@@ -370,6 +363,7 @@
         // Full size of the wallpaper (usually larger than bounds above to parallax scroll when
         // swiping through Launcher pages).
         final Rect wallpaperFrame = wallpaperWin.getFrame();
+        WallpaperWindowToken token = wallpaperWin.mToken.asWallpaperToken();
 
         final int diffWidth = wallpaperFrame.width() - lastWallpaperBounds.width();
         final int diffHeight = wallpaperFrame.height() - lastWallpaperBounds.height();
@@ -394,10 +388,10 @@
         // The 0 to 1 scale is because the "length" varies depending on how many home screens you
         // have, so 0 is the left of the first home screen, and 1 is the right of the last one (for
         // LTR, and the opposite for RTL).
-        float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
+        float wpx = token.mWallpaperX >= 0 ? token.mWallpaperX : defaultWallpaperX;
         // "Wallpaper X step size" is how much of that 0-1 is one "page" of the home screen
         // when scrolling.
-        float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
+        float wpxs = token.mWallpaperXStep >= 0 ? token.mWallpaperXStep : -1.0f;
         // Difference between width of wallpaper image, and the last size of the wallpaper.
         // This is the horizontal surplus from the prior configuration.
         int availw = diffWidth;
@@ -406,10 +400,10 @@
                 wallpaperWin.isRtl());
         availw -= displayOffset;
         int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
-        if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+        if (token.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
             // if device is LTR, then offset wallpaper to the left (the wallpaper is drawn
             // always starting from the left of the screen).
-            offset += mLastWallpaperDisplayOffsetX;
+            offset += token.mWallpaperDisplayOffsetX;
         } else if (!wallpaperWin.isRtl()) {
             // In RTL the offset is calculated so that the wallpaper ends up right aligned (see
             // offset above).
@@ -423,11 +417,11 @@
             rawChanged = true;
         }
 
-        float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
-        float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
+        float wpy = token.mWallpaperY >= 0 ? token.mWallpaperY : 0.5f;
+        float wpys = token.mWallpaperYStep >= 0 ? token.mWallpaperYStep : -1.0f;
         offset = diffHeight > 0 ? -(int) (diffHeight * wpy + .5f) : 0;
-        if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
-            offset += mLastWallpaperDisplayOffsetY;
+        if (token.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+            offset += token.mWallpaperDisplayOffsetY;
         }
         newYOffset = offset;
 
@@ -549,8 +543,10 @@
     void setWallpaperZoomOut(WindowState window, float zoom) {
         if (Float.compare(window.mWallpaperZoomOut, zoom) != 0) {
             window.mWallpaperZoomOut = zoom;
-            mShouldUpdateZoom = true;
-            updateWallpaperOffsetLocked(window, false);
+            computeLastWallpaperZoomOut();
+            for (WallpaperWindowToken token : mWallpaperTokens) {
+                token.updateWallpaperOffset(false);
+            }
         }
     }
 
@@ -598,43 +594,48 @@
             // zoom effect from home.
             target = changingTarget;
         }
-        if (target != null) {
-            if (target.mWallpaperX >= 0) {
-                mLastWallpaperX = target.mWallpaperX;
-            } else if (changingTarget.mWallpaperX >= 0) {
-                mLastWallpaperX = changingTarget.mWallpaperX;
-            }
-            if (target.mWallpaperY >= 0) {
-                mLastWallpaperY = target.mWallpaperY;
-            } else if (changingTarget.mWallpaperY >= 0) {
-                mLastWallpaperY = changingTarget.mWallpaperY;
-            }
-            computeLastWallpaperZoomOut();
-            if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
-                mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
-            } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
-                mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
-            }
-            if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
-                mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
-            } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
-                mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
-            }
-            if (target.mWallpaperXStep >= 0) {
-                mLastWallpaperXStep = target.mWallpaperXStep;
-            } else if (changingTarget.mWallpaperXStep >= 0) {
-                mLastWallpaperXStep = changingTarget.mWallpaperXStep;
-            }
-            if (target.mWallpaperYStep >= 0) {
-                mLastWallpaperYStep = target.mWallpaperYStep;
-            } else if (changingTarget.mWallpaperYStep >= 0) {
-                mLastWallpaperYStep = changingTarget.mWallpaperYStep;
-            }
-        }
 
-        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
-            mWallpaperTokens.get(curTokenNdx).updateWallpaperOffset(sync);
+        WallpaperWindowToken token = getTokenForTarget(target);
+        if (token == null) return;
+
+        if (target.mWallpaperX >= 0) {
+            token.mWallpaperX = target.mWallpaperX;
+        } else if (changingTarget.mWallpaperX >= 0) {
+            token.mWallpaperX = changingTarget.mWallpaperX;
         }
+        if (target.mWallpaperY >= 0) {
+            token.mWallpaperY = target.mWallpaperY;
+        } else if (changingTarget.mWallpaperY >= 0) {
+            token.mWallpaperY = changingTarget.mWallpaperY;
+        }
+        if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+            token.mWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
+        } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+            token.mWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
+        }
+        if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+            token.mWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
+        } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+            token.mWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
+        }
+        if (target.mWallpaperXStep >= 0) {
+            token.mWallpaperXStep = target.mWallpaperXStep;
+        } else if (changingTarget.mWallpaperXStep >= 0) {
+            token.mWallpaperXStep = changingTarget.mWallpaperXStep;
+        }
+        if (target.mWallpaperYStep >= 0) {
+            token.mWallpaperYStep = target.mWallpaperYStep;
+        } else if (changingTarget.mWallpaperYStep >= 0) {
+            token.mWallpaperYStep = changingTarget.mWallpaperYStep;
+        }
+        token.updateWallpaperOffset(sync);
+    }
+
+    private WallpaperWindowToken getTokenForTarget(WindowState target) {
+        if (target == null) return null;
+        WindowState window = mFindResults.getTopWallpaper(
+                target.canShowWhenLocked() && mService.isKeyguardLocked());
+        return window == null ? null : window.mToken.asWallpaperToken();
     }
 
     void clearLastWallpaperTimeoutTime() {
@@ -805,10 +806,11 @@
         // all wallpapers go behind it.
         findWallpaperTarget();
         updateWallpaperWindowsTarget(mFindResults);
+        WallpaperWindowToken token = getTokenForTarget(mWallpaperTarget);
 
         // 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;
+        final boolean visible = token != null;
         if (DEBUG_WALLPAPER) {
             Slog.v(TAG, "Wallpaper visibility: " + visible + " at display "
                     + mDisplayContent.getDisplayId());
@@ -816,19 +818,18 @@
 
         if (visible) {
             if (mWallpaperTarget.mWallpaperX >= 0) {
-                mLastWallpaperX = mWallpaperTarget.mWallpaperX;
-                mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
+                token.mWallpaperX = mWallpaperTarget.mWallpaperX;
+                token.mWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
             }
-            computeLastWallpaperZoomOut();
             if (mWallpaperTarget.mWallpaperY >= 0) {
-                mLastWallpaperY = mWallpaperTarget.mWallpaperY;
-                mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
+                token.mWallpaperY = mWallpaperTarget.mWallpaperY;
+                token.mWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
             }
             if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
-                mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
+                token.mWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
             }
             if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
-                mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
+                token.mWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
             }
         }
 
@@ -1020,13 +1021,11 @@
      * we'll have conflicts and break the "depth system" mental model.
      */
     private void computeLastWallpaperZoomOut() {
-        if (mShouldUpdateZoom) {
-            mLastWallpaperZoomOut = 0;
-            mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true);
-            mShouldUpdateZoom = false;
-        }
+        mLastWallpaperZoomOut = 0;
+        mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true);
     }
 
+
     private float zoomOutToScale(float zoomOut) {
         return MathUtils.lerp(mMinWallpaperScale, mMaxWallpaperScale, 1 - zoomOut);
     }
@@ -1034,19 +1033,28 @@
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("displayId="); pw.println(mDisplayContent.getDisplayId());
         pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
+        pw.print(prefix); pw.print("mLastWallpaperZoomOut="); pw.println(mLastWallpaperZoomOut);
         if (mPrevWallpaperTarget != null) {
             pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget);
         }
-        pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX);
-        pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
-        if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE
-                || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
-            pw.print(prefix);
-            pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX);
-            pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY);
+
+        for (WallpaperWindowToken t : mWallpaperTokens) {
+            pw.print(prefix); pw.println("token " + t + ":");
+            pw.print(prefix); pw.print("  canShowWhenLocked="); pw.println(t.canShowWhenLocked());
+            dumpValue(pw, prefix, "mWallpaperX", t.mWallpaperX);
+            dumpValue(pw, prefix, "mWallpaperY", t.mWallpaperY);
+            dumpValue(pw, prefix, "mWallpaperXStep", t.mWallpaperXStep);
+            dumpValue(pw, prefix, "mWallpaperYStep", t.mWallpaperYStep);
+            dumpValue(pw, prefix, "mWallpaperDisplayOffsetX", t.mWallpaperDisplayOffsetX);
+            dumpValue(pw, prefix, "mWallpaperDisplayOffsetY", t.mWallpaperDisplayOffsetY);
         }
     }
 
+    private void dumpValue(PrintWriter pw, String prefix, String valueName, float value) {
+        pw.print(prefix); pw.print("  " + valueName + "=");
+        pw.println(value >= 0 ? value : "NA");
+    }
+
     /** Helper class for storing the results of a wallpaper target find operation. */
     final private static class FindWallpaperTargetResult {
 
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index c7fd147..50ef52a 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -42,6 +42,12 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperWindowToken" : TAG_WM;
 
     private boolean mShowWhenLocked = false;
+    float mWallpaperX = -1;
+    float mWallpaperY = -1;
+    float mWallpaperXStep = -1;
+    float mWallpaperYStep = -1;
+    int mWallpaperDisplayOffsetX = Integer.MIN_VALUE;
+    int mWallpaperDisplayOffsetY = Integer.MIN_VALUE;
 
     WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
             DisplayContent dc, boolean ownerCanManageAppTokens) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerFlags.java b/services/core/java/com/android/server/wm/WindowManagerFlags.java
new file mode 100644
index 0000000..00b9b4c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowManagerFlags.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 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 com.android.window.flags.Flags;
+
+/**
+ * Utility class to read the flags used in the WindowManager server.
+ *
+ * It is not very cheap to read trunk stable flag, so having a centralized place to cache the flag
+ * values in the system server side.
+ *
+ * Flags should be defined in `core.java.android.window.flags` to allow access from client side.
+ *
+ * To override flag:
+ *   adb shell device_config put [namespace] [package].[name] [true/false]
+ *   adb reboot
+ *
+ * To access in wm:
+ *   {@link WindowManagerService#mFlags}
+ *
+ * Notes:
+ *   The system may use flags at anytime, so changing flags will only take effect after device
+ *   reboot. Otherwise, it may result unexpected behavior, such as broken transition.
+ *   When a flag needs to be read from both the server side and the client side, changing the flag
+ *   value will result difference in server and client until device reboot.
+ */
+class WindowManagerFlags {
+
+    /* Start Available Flags */
+
+    final boolean mSyncWindowConfigUpdateFlag = Flags.syncWindowConfigUpdateFlag();
+
+    /* End Available Flags */
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 82452cc..f339d24 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -249,6 +249,7 @@
 import android.view.Gravity;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.ICrossWindowBlurEnabledListener;
+import android.view.IDecorViewGestureListener;
 import android.view.IDisplayChangeWindowController;
 import android.view.IDisplayFoldListener;
 import android.view.IDisplayWindowInsetsController;
@@ -303,6 +304,7 @@
 import android.window.ISurfaceSyncGroupCompletedListener;
 import android.window.ITaskFpsCallback;
 import android.window.ScreenCapture;
+import android.window.SystemPerformanceHinter;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerToken;
 import android.window.WindowContextInfo;
@@ -546,6 +548,8 @@
     @VisibleForTesting
     WindowManagerPolicy mPolicy;
 
+    final WindowManagerFlags mFlags;
+
     final IActivityManager mActivityManager;
     final ActivityManagerInternal mAmInternal;
     final UserManagerInternal mUmInternal;
@@ -1035,6 +1039,8 @@
         sThreadPriorityBooster.reset();
     }
 
+    SystemPerformanceHinter mSystemPerformanceHinter;
+
     void openSurfaceTransaction() {
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction");
@@ -1152,6 +1158,7 @@
         mGlobalLock = atm.getGlobalLock();
         mAtmService = atm;
         mContext = context;
+        mFlags = new WindowManagerFlags();
         mIsPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
         mAllowBootMessages = showBootMsgs;
         mLimitedAlphaCompositing = context.getResources().getBoolean(
@@ -1328,6 +1335,13 @@
         mBlurController = new BlurController(mContext, mPowerManager);
         mTaskFpsCallbackController = new TaskFpsCallbackController(mContext);
         mAccessibilityController = new AccessibilityController(this);
+        mSystemPerformanceHinter = new SystemPerformanceHinter(mContext, displayId -> {
+            synchronized (mGlobalLock) {
+                DisplayContent dc = mRoot.getDisplayContent(displayId);
+                return (dc == null) ? null : dc.getSurfaceControl();
+            }
+
+        }, mTransactionFactory);
     }
 
     DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() {
@@ -2493,14 +2507,6 @@
                 outInsetsState.set(win.getCompatInsetsState(), true /* copySources */);
             }
 
-            // TODO (b/298562855): Remove this after identifying the reason why the frame is empty.
-            if (win.mAttrs.providedInsets != null && win.getFrame().isEmpty()) {
-                Slog.w(TAG, "Empty frame of " + win
-                        + " configChanged=" + configChanged
-                        + " frame=" + win.getFrame().toShortString()
-                        + " attrs=" + attrs);
-            }
-
             ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",
                     win, focusMayChange);
 
@@ -3108,10 +3114,15 @@
 
     @Override
     public void notifyKeyguardTrustedChanged() {
-        synchronized (mGlobalLock) {
-            if (mAtmService.mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
-                mRoot.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                if (mAtmService.mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
+                    mRoot.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+                }
             }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -4637,8 +4648,9 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
-                throw new IllegalArgumentException("Trying to register visibility event "
-                        + "for invalid display: " + displayId);
+                throw new IllegalArgumentException(
+                        "Trying to register system gesture exclusion event for invalid display: "
+                                + displayId);
             }
             displayContent.registerSystemGestureExclusionListener(listener);
         }
@@ -4650,13 +4662,64 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
-                throw new IllegalArgumentException("Trying to register visibility event "
-                        + "for invalid display: " + displayId);
+                throw new IllegalArgumentException(
+                        "Trying to unregister system gesture exclusion event for invalid display: "
+                                + displayId);
             }
             displayContent.unregisterSystemGestureExclusionListener(listener);
         }
     }
 
+    @Override
+    public void registerDecorViewGestureListener(
+            IDecorViewGestureListener listener, int displayId) {
+        if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
+                "registerDecorViewGestureListener()")) {
+            throw new SecurityException("Requires MONITOR_INPUT permission");
+        }
+        synchronized (mGlobalLock) {
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            if (displayContent == null) {
+                throw new IllegalArgumentException(
+                        "Trying to register DecorView gesture event listener"
+                                + "for invalid display: "
+                                + displayId);
+            }
+            displayContent.registerDecorViewGestureListener(listener);
+        }
+    }
+
+    @Override
+    public void unregisterDecorViewGestureListener(
+            IDecorViewGestureListener listener, int displayId) {
+        if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
+                "unregisterSystemGestureExclusionListener()")) {
+            throw new SecurityException("Requires MONITOR_INPUT permission");
+        }
+        synchronized (mGlobalLock) {
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            if (displayContent == null) {
+                throw new IllegalArgumentException(
+                        "Trying to unregister DecorView gesture event listener"
+                                + "for invalid display: "
+                                + displayId);
+            }
+            displayContent.unregisterDecorViewGestureListener(listener);
+        }
+    }
+
+    void reportDecorViewGestureChanged(Session session, IWindow window, boolean intercepted) {
+        synchronized (mGlobalLock) {
+            final WindowState win =
+                    windowForClientLocked(session, window, false /* throwOnError */);
+            if (win == null) {
+                return;
+            }
+            win.getDisplayContent()
+                    .updateDecorViewGestureIntercepted(win.mToken.token, intercepted);
+        }
+    }
+
     void reportSystemGestureExclusionChanged(Session session, IWindow window,
             List<Rect> exclusionRects) {
         synchronized (mGlobalLock) {
@@ -8803,7 +8866,7 @@
     void grantInputChannel(Session session, int callingUid, int callingPid, int displayId,
             SurfaceControl surface, IWindow window, IBinder hostInputToken,
             int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken,
-            IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) {
+            IBinder inputTransferToken, String inputHandleName, InputChannel outInputChannel) {
         final int sanitizedType = sanitizeWindowType(session, displayId, windowToken, type);
         final InputApplicationHandle applicationHandle;
         final String name;
@@ -8812,7 +8875,7 @@
             EmbeddedWindowController.EmbeddedWindow win =
                     new EmbeddedWindowController.EmbeddedWindow(session, this, window,
                             mInputToWindowMap.get(hostInputToken), callingUid, callingPid,
-                            sanitizedType, displayId, focusGrantToken, inputHandleName,
+                            sanitizedType, displayId, inputTransferToken, inputHandleName,
                             (flags & FLAG_NOT_FOCUSABLE) == 0);
             win.openInputChannel(outInputChannel);
             mEmbeddedWindowController.add(outInputChannel.getToken(), win);
@@ -8884,11 +8947,6 @@
             h.inputConfig |= InputConfig.NOT_FOCUSABLE;
         }
 
-        //  Check private trusted overlay flag to set trustedOverlay field of input window handle.
-        if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
-            h.inputConfig |= InputConfig.TRUSTED_OVERLAY;
-        }
-
         h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
         h.ownerUid = callingUid;
         h.ownerPid = callingPid;
@@ -8908,6 +8966,8 @@
         }
 
         final SurfaceControl.Transaction t = mTransactionFactory.get();
+        //  Check private trusted overlay flag to set trustedOverlay field of input window handle.
+        h.setTrustedOverlay(t, surface, (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0);
         t.setInputWindowInfo(surface, h);
         t.apply();
         t.close();
@@ -9139,10 +9199,10 @@
         return mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId);
     }
 
-    void grantEmbeddedWindowFocus(Session session, IBinder focusToken, boolean grantFocus) {
+    void grantEmbeddedWindowFocus(Session session, IBinder inputTransferToken, boolean grantFocus) {
         synchronized (mGlobalLock) {
             final EmbeddedWindowController.EmbeddedWindow embeddedWindow =
-                    mEmbeddedWindowController.getByFocusToken(focusToken);
+                    mEmbeddedWindowController.getByInputTransferToken(inputTransferToken);
             if (embeddedWindow == null) {
                 Slog.e(TAG, "Embedded window not found");
                 return;
@@ -9187,8 +9247,8 @@
         }
     }
 
-    void grantEmbeddedWindowFocus(Session session, IWindow callingWindow, IBinder targetFocusToken,
-                                  boolean grantFocus) {
+    void grantEmbeddedWindowFocus(Session session, IWindow callingWindow,
+            IBinder inputTransferToken, boolean grantFocus) {
         synchronized (mGlobalLock) {
             final WindowState hostWindow =
                     windowForClientLocked(session, callingWindow, false /* throwOnError*/);
@@ -9201,7 +9261,7 @@
                 return;
             }
             final EmbeddedWindowController.EmbeddedWindow embeddedWindow =
-                    mEmbeddedWindowController.getByFocusToken(targetFocusToken);
+                    mEmbeddedWindowController.getByInputTransferToken(inputTransferToken);
             if (embeddedWindow == null) {
                 Slog.e(TAG, "Embedded window not found");
                 return;
@@ -9430,7 +9490,7 @@
                     throw new IllegalArgumentException(
                             "Failed to find matching task for taskId=" + taskId);
                 }
-                taskSnapshot = mTaskSnapshotController.captureSnapshot(task, false);
+                taskSnapshot = mTaskSnapshotController.captureSnapshot(task);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index f8e9a56..dd9a88f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -41,6 +41,7 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK;
@@ -1088,6 +1089,26 @@
                 }
                 break;
             }
+            case HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK: {
+                final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
+                Task pipTask = container.asTask();
+                if (pipTask == null) {
+                    break;
+                }
+                ActivityRecord[] pipActivity = new ActivityRecord[1];
+                pipTask.forAllActivities((activity) -> {
+                    if (activity.pictureInPictureArgs != null) {
+                        pipActivity[0] = activity;
+                    }
+                });
+
+                Rect entryBounds = hop.getBounds();
+                mService.mRootWindowContainer.moveActivityToPinnedRootTask(
+                        pipActivity[0], null /* launchIntoPipHostActivity */,
+                        "moveActivityToPinnedRootTask", null /* transition */, entryBounds);
+                effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                break;
+            }
             case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: {
                 if (finishTransition == null) break;
                 final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ebef606..4beec2b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -178,6 +178,7 @@
 import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
 import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
 import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
+import static com.android.window.flags.Flags.surfaceTrustedOverlay;
 
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
@@ -1110,7 +1111,9 @@
         mInputWindowHandle.setName(getName());
         mInputWindowHandle.setPackageName(mAttrs.packageName);
         mInputWindowHandle.setLayoutParamsType(mAttrs.type);
-        mInputWindowHandle.setTrustedOverlay(shouldWindowHandleBeTrusted(s));
+        if (!surfaceTrustedOverlay()) {
+            mInputWindowHandle.setTrustedOverlay(isWindowTrustedOverlay());
+        }
         if (DEBUG) {
             Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
                             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -1185,12 +1188,12 @@
         }
     }
 
-    boolean shouldWindowHandleBeTrusted(Session s) {
+    public boolean isWindowTrustedOverlay() {
         return InputMonitor.isTrustedOverlay(mAttrs.type)
                 || ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
-                        && s.mCanAddInternalSystemWindow)
+                        && mSession.mCanAddInternalSystemWindow)
                 || ((mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0
-                        && s.mCanCreateSystemApplicationOverlay);
+                        && mSession.mCanCreateSystemApplicationOverlay);
     }
 
     int getTouchOcclusionMode() {
@@ -5187,6 +5190,9 @@
             updateFrameRateSelectionPriorityIfNeeded();
             updateScaleIfNeeded();
             mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
+            if (surfaceTrustedOverlay()) {
+                getSyncTransaction().setTrustedOverlay(mSurfaceControl, isWindowTrustedOverlay());
+            }
         }
         super.prepareSurfaces();
     }
@@ -5939,7 +5945,13 @@
     }
 
     boolean isTrustedOverlay() {
-        return mInputWindowHandle.isTrustedOverlay();
+        if (surfaceTrustedOverlay()) {
+            WindowState parentWindow = getParentWindow();
+            return isWindowTrustedOverlay() || (parentWindow != null
+                    && parentWindow.isWindowTrustedOverlay());
+        } else {
+            return mInputWindowHandle.isTrustedOverlay();
+        }
     }
 
     public boolean receiveFocusFromTapOutside() {
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index ec5378f..bc70658 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -78,6 +78,7 @@
         "onload.cpp",
         ":lib_cachedAppOptimizer_native",
         ":lib_gameManagerService_native",
+        ":lib_oomConnection_native",
     ],
 
     include_dirs: [
@@ -122,6 +123,7 @@
         "libhardware_legacy",
         "libhidlbase",
         "libmeminfo",
+        "libmemevents",
         "libmemtrackproxy",
         "libmtp",
         "libnativehelper",
@@ -239,3 +241,8 @@
         "com_android_server_app_GameManagerService.cpp",
     ],
 }
+
+filegroup {
+    name: "lib_oomConnection_native",
+    srcs: ["com_android_server_am_OomConnection.cpp",],
+}
diff --git a/services/core/jni/com_android_server_am_OomConnection.cpp b/services/core/jni/com_android_server_am_OomConnection.cpp
new file mode 100644
index 0000000..e892d23
--- /dev/null
+++ b/services/core/jni/com_android_server_am_OomConnection.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#define LOG_TAG "OomConnection"
+
+#include <core_jni_helpers.h>
+#include <jni.h>
+#include <memevents/memevents.h>
+
+namespace android {
+
+// Used to cache the results of the JNI name lookup
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+} sOomKillRecordInfo;
+
+static memevents::MemEventListener memevent_listener;
+
+/**
+ * Initialize listening and waiting for new out-of-memory (OOM) events to occur.
+ * Once a OOM event is detected, we then fetch the list of OOM kills, and return
+ * a corresponding java array with the information gathered.
+ *
+ * In the case that we encounter an error, we make sure to close the epfd, and
+ * the OOM file descriptor, by calling `deregisterAllEvents()`.
+ *
+ * @return list of `android.os.OomKillRecord`
+ * @throws java.lang.RuntimeException
+ */
+static jobjectArray android_server_am_OomConnection_waitOom(JNIEnv* env, jobject) {
+    const memevents::MemEvent oom_event = memevents::MemEvent::OOM_KILL;
+    if (!memevent_listener.registerEvent(oom_event)) {
+        memevent_listener.deregisterAllEvents();
+        jniThrowRuntimeException(env, "listener failed to register to OOM events");
+        return nullptr;
+    }
+
+    memevents::MemEvent event_received;
+    do {
+        event_received = memevent_listener.listen();
+        if (event_received == memevents::MemEvent::ERROR) {
+            memevent_listener.deregisterAllEvents();
+            jniThrowRuntimeException(env, "listener received error event");
+            return nullptr;
+        }
+    } while (event_received != oom_event);
+
+    std::vector<memevents::OomKill> oom_events;
+    if (!memevent_listener.getOomEvents(oom_events)) {
+        memevent_listener.deregisterAllEvents();
+        jniThrowRuntimeException(env, "Failed to get OOM events");
+        return nullptr;
+    }
+
+    jobjectArray java_oom_array =
+            env->NewObjectArray(oom_events.size(), sOomKillRecordInfo.clazz, nullptr);
+    if (java_oom_array == NULL) {
+        memevent_listener.deregisterAllEvents();
+        jniThrowRuntimeException(env, "Failed to create OomKillRecord array");
+        return nullptr;
+    }
+
+    for (int i = 0; i < oom_events.size(); i++) {
+        const memevents::OomKill oom_event = oom_events[i];
+        jstring process_name = env->NewStringUTF(oom_event.process_name);
+        if (process_name == NULL) {
+            memevent_listener.deregisterAllEvents();
+            jniThrowRuntimeException(env, "Failed creating java string for process name");
+        }
+        jobject java_oom_kill = env->NewObject(sOomKillRecordInfo.clazz, sOomKillRecordInfo.ctor,
+                                               oom_event.timestamp_ms, oom_event.pid, oom_event.uid,
+                                               process_name, oom_event.oom_score_adj);
+        if (java_oom_kill == NULL) {
+            memevent_listener.deregisterAllEvents();
+            jniThrowRuntimeException(env, "Failed to create OomKillRecord object");
+            return java_oom_array;
+        }
+        env->SetObjectArrayElement(java_oom_array, i, java_oom_kill);
+    }
+    return java_oom_array;
+}
+
+static const JNINativeMethod sOomConnectionMethods[] = {
+        /* name, signature, funcPtr */
+        {"waitOom", "()[Landroid/os/OomKillRecord;",
+         (void*)android_server_am_OomConnection_waitOom},
+};
+
+int register_android_server_am_OomConnection(JNIEnv* env) {
+    sOomKillRecordInfo.clazz = FindClassOrDie(env, "android/os/OomKillRecord");
+    sOomKillRecordInfo.clazz = MakeGlobalRefOrDie(env, sOomKillRecordInfo.clazz);
+
+    sOomKillRecordInfo.ctor =
+            GetMethodIDOrDie(env, sOomKillRecordInfo.clazz, "<init>", "(JIILjava/lang/String;S)V");
+
+    return RegisterMethodsOrDie(env, "com/android/server/am/OomConnection", sOomConnectionMethods,
+                                NELEM(sOomConnectionMethods));
+}
+} // namespace android
\ No newline at end of file
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index f6f6737..df44895 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -52,6 +52,7 @@
 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
 int register_android_server_SyntheticPasswordManager(JNIEnv* env);
 int register_android_hardware_display_DisplayViewport(JNIEnv* env);
+int register_android_server_am_OomConnection(JNIEnv* env);
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
 int register_android_server_am_LowMemDetector(JNIEnv* env);
 int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env);
@@ -112,6 +113,7 @@
     register_android_server_storage_AppFuse(env);
     register_android_server_SyntheticPasswordManager(env);
     register_android_hardware_display_DisplayViewport(env);
+    register_android_server_am_OomConnection(env);
     register_android_server_am_CachedAppOptimizer(env);
     register_android_server_am_LowMemDetector(env);
     register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env);
diff --git a/services/core/jni/tvinput/JTvInputHal.cpp b/services/core/jni/tvinput/JTvInputHal.cpp
index 74fdabf..68e2c9a 100644
--- a/services/core/jni/tvinput/JTvInputHal.cpp
+++ b/services/core/jni/tvinput/JTvInputHal.cpp
@@ -168,6 +168,24 @@
     return list;
 }
 
+static const std::map<std::pair<AidlAudioDeviceType, std::string>, audio_devices_t>
+        aidlToNativeAudioType = {
+    {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_ANALOG},
+        AUDIO_DEVICE_IN_LINE},
+    {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_HDMI},
+        AUDIO_DEVICE_IN_HDMI},
+    {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_HDMI_ARC},
+        AUDIO_DEVICE_IN_HDMI_ARC},
+    {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_HDMI_EARC},
+        AUDIO_DEVICE_IN_HDMI_EARC},
+    {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_IP_V4},
+        AUDIO_DEVICE_IN_IP},
+    {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_SPDIF},
+        AUDIO_DEVICE_IN_SPDIF},
+    {{AidlAudioDeviceType::IN_LOOPBACK, ""}, AUDIO_DEVICE_IN_LOOPBACK},
+    {{AidlAudioDeviceType::IN_TV_TUNER, ""}, AUDIO_DEVICE_IN_TV_TUNER},
+};
+
 void JTvInputHal::onDeviceAvailable(const TvInputDeviceInfoWrapper& info) {
     {
         Mutex::Autolock autoLock(&mLock);
@@ -187,9 +205,15 @@
     if (info.isHidl) {
         hidlSetUpAudioInfo(env, builder, info);
     } else {
-        AidlAudioDeviceType audioType = info.aidlAudioDevice.type.type;
-        env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioType, audioType);
-        if (audioType != AidlAudioDeviceType::NONE) {
+        auto it = aidlToNativeAudioType.find({info.aidlAudioDevice.type.type,
+                                    info.aidlAudioDevice.type.connection});
+        audio_devices_t nativeAudioType = AUDIO_DEVICE_NONE;
+        if (it != aidlToNativeAudioType.end()) {
+            nativeAudioType = it->second;
+        }
+        env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioType,
+            nativeAudioType);
+        if (info.aidlAudioDevice.type.type != AidlAudioDeviceType::NONE) {
             std::stringstream ss;
             switch (info.aidlAudioDevice.address.getTag()) {
                 case AidlAudioDeviceAddress::id:
diff --git a/services/core/jni/tvinput/JTvInputHal.h b/services/core/jni/tvinput/JTvInputHal.h
index e8b1c99..b7b4b16 100644
--- a/services/core/jni/tvinput/JTvInputHal.h
+++ b/services/core/jni/tvinput/JTvInputHal.h
@@ -54,6 +54,7 @@
 
 using AidlAudioDevice = ::aidl::android::media::audio::common::AudioDevice;
 using AidlAudioDeviceAddress = ::aidl::android::media::audio::common::AudioDeviceAddress;
+using AidlAudioDeviceDescription = ::aidl::android::media::audio::common::AudioDeviceDescription;
 using AidlAudioDeviceType = ::aidl::android::media::audio::common::AudioDeviceType;
 using AidlITvInput = ::aidl::android::hardware::tv::input::ITvInput;
 using AidlNativeHandle = ::aidl::android::hardware::common::NativeHandle;
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 d0a9c45..debd891 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -46,6 +46,8 @@
                     <xs:annotation name="nonnull"/>
                     <xs:annotation name="final"/>
                 </xs:element>
+                <xs:element type="powerThrottlingConfig" name="powerThrottlingConfig" minOccurs="0"
+                            maxOccurs="1"/>
                 <xs:element type="luxThrottling" name="luxThrottling" minOccurs="0"
                             maxOccurs="1"/>
                 <xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0"
@@ -350,6 +352,43 @@
         </xs:sequence>
     </xs:complexType>
 
+    <xs:complexType name="powerThrottlingMap">
+        <xs:sequence>
+            <xs:element name="powerThrottlingPoint" type="powerThrottlingPoint" maxOccurs="unbounded" minOccurs="1">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+        <xs:attribute name="id" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:complexType name="powerThrottlingPoint">
+        <xs:sequence>
+            <xs:element type="thermalStatus" name="thermalStatus">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+            <xs:element type="nonNegativeDecimal" name="powerQuotaMilliWatts">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="powerThrottlingConfig">
+        <xs:element type="nonNegativeDecimal" name="brightnessLowestCapAllowed">
+            <xs:annotation name="nonnull"/>
+            <xs:annotation name="final"/>
+        </xs:element>
+        <xs:element name="pollingWindowMillis" type="xs:nonNegativeInteger">
+            <xs:annotation name="nonnull"/>
+            <xs:annotation name="final"/>
+        </xs:element>
+        <xs:element type="powerThrottlingMap" name="powerThrottlingMap" maxOccurs="unbounded">
+                <xs:annotation name="final"/>
+        </xs:element>
+    </xs:complexType>
+
     <xs:complexType name="nitsMap">
         <xs:sequence>
             <xs:element name="point" type="point" maxOccurs="unbounded" minOccurs="2">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 949b1f2..2d27f0c 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -106,6 +106,7 @@
     method public final com.android.server.display.config.SensorDetails getLightSensor();
     method public com.android.server.display.config.LuxThrottling getLuxThrottling();
     method @Nullable public final String getName();
+    method public com.android.server.display.config.PowerThrottlingConfig getPowerThrottlingConfig();
     method public final com.android.server.display.config.SensorDetails getProxSensor();
     method public com.android.server.display.config.DisplayQuirks getQuirks();
     method public com.android.server.display.config.RefreshRateConfigs getRefreshRate();
@@ -138,6 +139,7 @@
     method public final void setLightSensor(com.android.server.display.config.SensorDetails);
     method public void setLuxThrottling(com.android.server.display.config.LuxThrottling);
     method public final void setName(@Nullable String);
+    method public void setPowerThrottlingConfig(com.android.server.display.config.PowerThrottlingConfig);
     method public final void setProxSensor(com.android.server.display.config.SensorDetails);
     method public void setQuirks(com.android.server.display.config.DisplayQuirks);
     method public void setRefreshRate(com.android.server.display.config.RefreshRateConfigs);
@@ -246,6 +248,30 @@
     method public final void setValue(@NonNull java.math.BigDecimal);
   }
 
+  public class PowerThrottlingConfig {
+    ctor public PowerThrottlingConfig();
+    method @NonNull public final java.math.BigDecimal getBrightnessLowestCapAllowed();
+    method @NonNull public final java.math.BigInteger getPollingWindowMillis();
+    method public final java.util.List<com.android.server.display.config.PowerThrottlingMap> getPowerThrottlingMap();
+    method public final void setBrightnessLowestCapAllowed(@NonNull java.math.BigDecimal);
+    method public final void setPollingWindowMillis(@NonNull java.math.BigInteger);
+  }
+
+  public class PowerThrottlingMap {
+    ctor public PowerThrottlingMap();
+    method public String getId();
+    method @NonNull public final java.util.List<com.android.server.display.config.PowerThrottlingPoint> getPowerThrottlingPoint();
+    method public void setId(String);
+  }
+
+  public class PowerThrottlingPoint {
+    ctor public PowerThrottlingPoint();
+    method @NonNull public final java.math.BigDecimal getPowerQuotaMilliWatts();
+    method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatus();
+    method public final void setPowerQuotaMilliWatts(@NonNull java.math.BigDecimal);
+    method public final void setThermalStatus(@NonNull com.android.server.display.config.ThermalStatus);
+  }
+
   public enum PredefinedBrightnessLimitNames {
     method public String getRawName();
     enum_constant public static final com.android.server.display.config.PredefinedBrightnessLimitNames _default;
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
index 57b5d00..4e95465 100644
--- a/services/core/xsd/display-layout-config/display-layout-config.xsd
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -52,6 +52,7 @@
             <xs:element name="address" type="xs:nonNegativeInteger"/>
             <xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" />
             <xs:element name="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
+            <xs:element name="powerThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
             <xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" />
             <xs:element name="leadDisplayAddress" type="xs:nonNegativeInteger" minOccurs="0" maxOccurs="1" />
         </xs:sequence>
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
index 2d4f7a4..195cae5 100644
--- a/services/core/xsd/display-layout-config/schema/current.txt
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -8,6 +8,7 @@
     method public String getDisplayGroup();
     method public java.math.BigInteger getLeadDisplayAddress();
     method public String getPosition();
+    method public String getPowerThrottlingMapId();
     method public String getRefreshRateThermalThrottlingMapId();
     method public String getRefreshRateZoneId();
     method public boolean isDefaultDisplay();
@@ -19,6 +20,7 @@
     method public void setEnabled(boolean);
     method public void setLeadDisplayAddress(java.math.BigInteger);
     method public void setPosition(String);
+    method public void setPowerThrottlingMapId(String);
     method public void setRefreshRateThermalThrottlingMapId(String);
     method public void setRefreshRateZoneId(String);
   }
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index b90f08e..3c190bf 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.ResultReceiver;
+import android.os.UserHandle;
 import android.service.credentials.CredentialProviderInfoFactory;
 import android.util.Slog;
 
@@ -171,7 +172,9 @@
                 .setAction(UUID.randomUUID().toString());
         //TODO: Create unique pending intent using request code and cancel any pre-existing pending
         // intents
-        return PendingIntent.getActivity(
-                mContext, /*requestCode=*/0, intent, PendingIntent.FLAG_IMMUTABLE);
+        return PendingIntent.getActivityAsUser(
+                mContext, /*requestCode=*/0, intent,
+                PendingIntent.FLAG_IMMUTABLE, /*options=*/null,
+                UserHandle.of(mUserId));
     }
 }
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 3eb6718..7bd1cc4 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -31,6 +31,7 @@
 import android.credentials.ui.GetCredentialProviderData;
 import android.credentials.ui.ProviderPendingIntentResponse;
 import android.os.ICancellationSignal;
+import android.service.autofill.Flags;
 import android.service.credentials.Action;
 import android.service.credentials.BeginGetCredentialOption;
 import android.service.credentials.BeginGetCredentialRequest;
@@ -42,6 +43,7 @@
 import android.service.credentials.RemoteEntry;
 import android.util.Pair;
 import android.util.Slog;
+import android.view.autofill.AutofillId;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -379,13 +381,23 @@
         // but does not resolve to a valid option. For now, not skipping it because
         // it may be possible that the provider adds their own extras and expects to receive
         // those and complete the flow.
-        if (mBeginGetOptionToCredentialOptionMap.get(id) == null) {
+        Intent intent = new Intent();
+        CredentialOption credentialOption = mBeginGetOptionToCredentialOptionMap.get(id);
+        if (credentialOption == null) {
             Slog.w(TAG, "Id from Credential Entry does not resolve to a valid option");
-            return new Intent();
+            return intent;
         }
-        return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST,
+        AutofillId autofillId = credentialOption
+                .getCandidateQueryData()
+                .getParcelable(CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId.class);
+        if (autofillId != null && Flags.autofillCredmanIntegration()) {
+            intent.putExtra(CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId);
+        }
+        return intent.putExtra(
+                CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST,
                 new GetCredentialRequest(
-                        mCallingAppInfo, List.of(mBeginGetOptionToCredentialOptionMap.get(id))));
+                        mCallingAppInfo,
+                        List.of(credentialOption)));
     }
 
     private Intent setUpFillInIntentWithQueryRequest() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6aa135a..49af89b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -241,6 +241,7 @@
 import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
 import static android.provider.Telephony.Carriers.INVALID_APN_ID;
 import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION;
+
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -871,17 +872,9 @@
             "enable_permission_based_access";
     private static final boolean DEFAULT_VALUE_PERMISSION_BASED_ACCESS_FLAG = false;
 
-    private static final String ENABLE_DEVICE_POLICY_ENGINE_FOR_FINANCE_FLAG =
-            "enable_device_policy_engine";
-    private static final boolean DEFAULT_ENABLE_DEVICE_POLICY_ENGINE_FOR_FINANCE_FLAG = true;
-
     // TODO(b/265683382) remove the flag after rollout.
     public static final boolean DEFAULT_KEEP_PROFILES_RUNNING_FLAG = false;
 
-    // TODO(b/261999445) remove the flag after rollout.
-    private static final String HEADLESS_FLAG = "headless";
-    private static final boolean DEFAULT_HEADLESS_FLAG = true;
-
     // TODO(b/266831522) remove the flag after rollout.
     private static final String APPLICATION_EXEMPTIONS_FLAG = "application_exemptions";
     private static final boolean DEFAULT_APPLICATION_EXEMPTIONS_FLAG = true;
@@ -4024,75 +4017,41 @@
     }
 
     private void clearDeviceOwnerUserRestriction(UserHandle userHandle) {
-        if (isHeadlessFlagEnabled()) {
-            for (int userId : mUserManagerInternal.getUserIds()) {
-                UserHandle user = UserHandle.of(userId);
-                // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the
-                // original state
-                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, user)) {
-                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
-                            false, user);
-                }
-                // When a device owner is set, the system automatically restricts adding a
-                // managed profile.
-                // Remove this restriction when the device owner is cleared.
-                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
-                        user)) {
-                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
-                            false,
-                            user);
-                }
-                // When a device owner is set, the system automatically restricts adding a
-                // clone profile.
-                // Remove this restriction when the device owner is cleared.
-                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, user)) {
-                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
-                            false, user);
-                }
-
-                // When a device owner is set, the system automatically restricts adding a
-                // private profile.
-                // Remove this restriction when the device owner is cleared.
-                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
-                        user)) {
-                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
-                            false, user);
-                }
-            }
-        } else {
-            // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state
-            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) {
-                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
-                        userHandle);
+        for (int userId : mUserManagerInternal.getUserIds()) {
+            UserHandle user = UserHandle.of(userId);
+            // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the
+            // original state
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, user)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
+                        false, user);
             }
             // When a device owner is set, the system automatically restricts adding a
             // managed profile.
             // Remove this restriction when the device owner is cleared.
             if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
-                    userHandle)) {
+                    user)) {
                 mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
                         false,
-                        userHandle);
+                        user);
             }
-            // When a device owner is set, the system automatically restricts adding a clone
-            // profile.
+            // When a device owner is set, the system automatically restricts adding a
+            // clone profile.
             // Remove this restriction when the device owner is cleared.
-            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
-                    userHandle)) {
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, user)) {
                 mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
-                        false,
-                        userHandle);
+                        false, user);
             }
 
             // When a device owner is set, the system automatically restricts adding a
             // private profile.
             // Remove this restriction when the device owner is cleared.
             if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
-                    userHandle)) {
+                    user)) {
                 mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
-                        false, userHandle);
+                        false, user);
             }
         }
+
     }
 
     /**
@@ -6475,7 +6434,7 @@
                          KeyChain.bindAsUser(mContext, userHandle)) {
                 IKeyChainService keyChain = keyChainConnection.getService();
                 return keyChain.setGrant(granteeUid, alias, hasGrant);
-            } catch (RemoteException e) {
+            } catch (RemoteException | AssertionError e) {
                 Slogf.e(LOG_TAG, "Setting grant for package.", e);
                 return false;
             }
@@ -7955,14 +7914,8 @@
                 hasCallingOrSelfPermission(permission.TRIGGER_LOST_MODE));
 
         synchronized (getLockObject()) {
-            // TODO(b/261999445): Remove
-            ActiveAdmin admin;
-            if (isHeadlessFlagEnabled()) {
-                admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
-            } else {
-                admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
-                        UserHandle.USER_SYSTEM);
-            }
+            ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
+
             Preconditions.checkState(admin != null,
                     "Lost mode location updates can only be sent on an organization-owned device.");
             mInjector.binderWithCleanCallingIdentity(() -> {
@@ -9448,39 +9401,24 @@
                 // profile, such that the admin on that managed profile has extended management
                 // capabilities that can affect the entire device (but not access private data
                 // on the primary profile).
-                if (isHeadlessFlagEnabled()) {
-                    for (int u : mUserManagerInternal.getUserIds()) {
-                        mUserManager.setUserRestriction(
-                                UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
-                                UserHandle.of(u));
-                        // Restrict adding a clone profile when a device owner is set on the device.
-                        // That is to prevent the co-existence of a clone profile and a device owner
-                        // on the same device.
-                        // CDD for reference : https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support
-                        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
-                                true,
-                                UserHandle.of(u));
-
-                        // Restrict adding a private profile when a device owner is set.
-                        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
-                                true,
-                                UserHandle.of(u));
-                    }
-                } else {
-                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
-                            true,
-                            UserHandle.of(userId));
+                for (int u : mUserManagerInternal.getUserIds()) {
+                    mUserManager.setUserRestriction(
+                            UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+                            UserHandle.of(u));
                     // Restrict adding a clone profile when a device owner is set on the device.
                     // That is to prevent the co-existence of a clone profile and a device owner
                     // on the same device.
                     // CDD for reference : https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support
                     mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
                             true,
-                            UserHandle.of(userId));
+                            UserHandle.of(u));
+
+                    // Restrict adding a private profile when a device owner is set.
                     mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
                             true,
-                            UserHandle.of(userId));
+                            UserHandle.of(u));
                 }
+
                 // TODO Send to system too?
                 sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId);
             });
@@ -15781,57 +15719,19 @@
         } else {
             long ident = mInjector.binderClearCallingIdentity();
             try {
-                // TODO(b/277908283): check in the policy engine instead of calling user manager.
-                List<UserManager.EnforcingUser> sources = mUserManager
-                        .getUserRestrictionSources(restriction, UserHandle.of(userId));
-                if (sources == null) {
-                    // The restriction is not enforced.
-                    return null;
-                }
-                int sizeBefore = sources.size();
-                if (sizeBefore > 1) {
-                    Slogf.d(LOG_TAG, "getEnforcingAdminAndUserDetailsInternal(%d, %s): "
-                            + "%d sources found, excluding those set by UserManager",
-                            userId, restriction, sizeBefore);
-                    sources = getDevicePolicySources(sources);
-                }
-                if (sources.isEmpty()) {
-                    // The restriction is not enforced (or is just enforced by the system)
+                if (getEnforcingAdminsForRestrictionInternal(userId, restriction).size() == 0) {
                     return null;
                 }
 
-                if (sources.size() > 1) {
-                    // In this case, we'll show an admin support dialog that does not
-                    // specify the admin.
-                    // TODO(b/128928355): if this restriction is enforced by multiple DPCs, return
-                    // the admin for the calling user.
-                    Slogf.w(LOG_TAG, "getEnforcingAdminAndUserDetailsInternal(%d, %s): multiple "
-                            + "sources for restriction %s on user %d",
-                            userId, restriction, restriction, userId);
+                ActiveAdmin admin = getMostProbableDPCAdminForLocalPolicy(userId);
+                if (admin != null) {
                     result = new Bundle();
-                    result.putInt(Intent.EXTRA_USER_ID, userId);
+                    result.putInt(Intent.EXTRA_USER_ID, admin.getUserHandle().getIdentifier());
+                    result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+                            admin.info.getComponent());
                     return result;
                 }
-                final UserManager.EnforcingUser enforcingUser = sources.get(0);
-                final int sourceType = enforcingUser.getUserRestrictionSource();
-                if (sourceType == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER
-                        || sourceType == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) {
-                    ActiveAdmin admin = getMostProbableDPCAdminForLocalPolicy(userId);
-                    if (admin != null) {
-                        result = new Bundle();
-                        result.putInt(Intent.EXTRA_USER_ID, admin.getUserHandle().getIdentifier());
-                        result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
-                                admin.info.getComponent());
-                        return result;
-                    }
-                } else if (sourceType == UserManager.RESTRICTION_SOURCE_SYSTEM) {
-                    /*
-                     * In this case, the user restriction is enforced by the system.
-                     * So we won't show an admin support intent, even if it is also
-                     * enforced by a profile/device owner.
-                     */
-                    return null;
-                }
+                return null;
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
@@ -20156,14 +20056,8 @@
         synchronized (getLockObject()) {
             // Only DO or COPE PO can turn on CC mode, so take a shortcut here and only look at
             // their ActiveAdmin, instead of iterating through all admins.
-            ActiveAdmin admin;
-            // TODO(b/261999445): remove
-            if (isHeadlessFlagEnabled()) {
-                admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
-            } else {
-                admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
-                        UserHandle.USER_SYSTEM);
-            }
+            ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
+
             return admin != null ? admin.mCommonCriteriaMode : false;
         }
     }
@@ -21430,7 +21324,7 @@
     }
 
     private void disallowAddUser() {
-        if (!isHeadlessFlagEnabled() || mIsAutomotive) {
+        if (mIsAutomotive) {
             // Auto still enables adding users due to the communal nature of those devices
             if (mInjector.userManagerIsHeadlessSystemUserMode()) {
                 Slogf.i(LOG_TAG, "Not setting DISALLOW_ADD_USER on headless system user mode.");
@@ -21748,14 +21642,7 @@
     }
 
     private boolean isUsbDataSignalingEnabledInternalLocked() {
-        // TODO(b/261999445): remove
-        ActiveAdmin admin;
-        if (isHeadlessFlagEnabled()) {
-            admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
-        } else {
-            admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
-                    UserHandle.USER_SYSTEM);
-        }
+        ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
         return admin == null || admin.mUsbDataSignalingEnabled;
     }
 
@@ -21822,14 +21709,7 @@
     @Override
     public int getMinimumRequiredWifiSecurityLevel() {
         synchronized (getLockObject()) {
-            ActiveAdmin admin;
-            // TODO(b/261999445): remove
-            if (isHeadlessFlagEnabled()) {
-                admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
-            } else {
-                admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
-                        UserHandle.USER_SYSTEM);
-            }
+            ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
             return (admin == null) ? DevicePolicyManager.WIFI_SECURITY_OPEN
                     : admin.mWifiMinimumSecurityLevel;
         }
@@ -23206,16 +23086,8 @@
                             || isProfileOwnerOfOrganizationOwnedDevice(caller));
         }
         synchronized (getLockObject()) {
-            // TODO(b/261999445): Remove
-            ActiveAdmin admin;
-            if (isHeadlessFlagEnabled()) {
-                admin =
+            ActiveAdmin admin =
                         getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
-            } else {
-                admin =
-                        getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
-                                UserHandle.USER_SYSTEM);
-            }
 
             if (admin != null) {
                 final String memtagProperty = "arm64.memtag.bootctl";
@@ -23248,29 +23120,14 @@
                             || isSystemUid(caller));
         }
         synchronized (getLockObject()) {
-            // TODO(b/261999445): Remove
-            ActiveAdmin admin;
-            if (isHeadlessFlagEnabled()) {
-                admin =
+            ActiveAdmin admin =
                         getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
-            } else {
-                admin =
-                        getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
-                                UserHandle.USER_SYSTEM);
-            }
             return admin != null
                     ? admin.mtePolicy
                     : DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY;
         }
     }
 
-    private boolean isHeadlessFlagEnabled() {
-        return DeviceConfig.getBoolean(
-                NAMESPACE_DEVICE_POLICY_MANAGER,
-                HEADLESS_FLAG,
-                DEFAULT_HEADLESS_FLAG);
-    }
-
     @Override
     public ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy() {
         synchronized (getLockObject()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index 16876ac..eb893fc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -251,7 +251,14 @@
 
     private int runSetDeviceOwner(PrintWriter pw) {
         parseArgs();
-        mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId);
+        boolean isAdminAdded = false;
+        try {
+            mService.setActiveAdmin(mComponent, /* refreshing= */ false, mUserId);
+            isAdminAdded = true;
+        } catch (IllegalArgumentException e) {
+            pw.printf("%s was already an admin for user %d. No need to set it again.\n",
+                    mComponent.flattenToShortString(), mUserId);
+        }
 
         try {
             if (!mService.setDeviceOwner(mComponent, mUserId,
@@ -260,8 +267,10 @@
                         "Can't set package " + mComponent + " as device owner.");
             }
         } catch (Exception e) {
-            // Need to remove the admin that we just added.
-            mService.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM);
+            if (isAdminAdded) {
+                // Need to remove the admin that we just added.
+                mService.removeActiveAdmin(mComponent, mUserId);
+            }
             throw e;
         }
 
diff --git a/services/foldables/devicestateprovider/tests/Android.bp b/services/foldables/devicestateprovider/tests/Android.bp
index a8db05e..84a6df3 100644
--- a/services/foldables/devicestateprovider/tests/Android.bp
+++ b/services/foldables/devicestateprovider/tests/Android.bp
@@ -20,11 +20,11 @@
         "foldable-device-state-provider",
         "androidx.test.rules",
         "junit",
-        "truth-prebuilt",
+        "truth",
         "mockito-target-extended-minus-junit4",
         "androidx.test.uiautomator_uiautomator",
         "androidx.test.ext.junit",
         "testables",
     ],
-    test_suites: ["device-tests"]
+    test_suites: ["device-tests"],
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 57fa12d..59f1edc 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -51,6 +51,7 @@
 import android.database.sqlite.SQLiteCompatibilityWalFlags;
 import android.database.sqlite.SQLiteGlobal;
 import android.graphics.GraphicsStatsService;
+import android.graphics.Typeface;
 import android.hardware.display.DisplayManagerInternal;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityModuleConnector;
@@ -264,6 +265,8 @@
             "com.android.server.backup.BackupManagerService$Lifecycle";
     private static final String APPWIDGET_SERVICE_CLASS =
             "com.android.server.appwidget.AppWidgetService";
+    private static final String ARC_SYSTEM_HEALTH_SERVICE =
+            "com.android.server.arc.health.ArcSystemHealthService";
     private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS =
             "com.android.server.voiceinteraction.VoiceInteractionManagerService";
     private static final String APP_HIBERNATION_SERVICE_CLASS =
@@ -914,6 +917,14 @@
             SystemServerInitThreadPool tp = SystemServerInitThreadPool.start();
             mDumper.addDumpable(tp);
 
+            // Lazily load the pre-installed system font map in SystemServer only if we're not doing
+            // the optimized font loading in the FontManagerService.
+            if (!com.android.text.flags.Flags.useOptimizedBoottimeFontLoading()
+                    && Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+                Slog.i(TAG, "Loading pre-installed system font map.");
+                Typeface.loadPreinstalledSystemFontMap();
+            }
+
             // Attach JVMTI agent if this is a debuggable build and the system property is set.
             if (Build.IS_DEBUGGABLE) {
                 // Property is of the form "library_path=parameters".
@@ -1287,6 +1298,12 @@
             }
         }
 
+        if (Build.IS_ARC) {
+            t.traceBegin("StartArcSystemHealthService");
+            mSystemServiceManager.startService(ARC_SYSTEM_HEALTH_SERVICE);
+            t.traceEnd();
+        }
+
         t.traceBegin("StartUserManagerService");
         mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
         t.traceEnd();
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
index 240585c..4addab3 100644
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
@@ -85,10 +85,10 @@
         appId: Int,
         userId: Int
     ) {
-        resetPermissionStates(packageName, userId)
+        resetRuntimePermissions(packageName, userId)
     }
 
-    private fun MutateStateScope.resetPermissionStates(packageName: String, userId: Int) {
+    fun MutateStateScope.resetRuntimePermissions(packageName: String, userId: Int) {
         // It's okay to skip resetting permissions for packages that are removed,
         // because their states will be trimmed in onPackageRemoved()/onAppIdRemoved()
         val packageState = newState.externalState.packageStates[packageName] ?: return
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index cee2524..2a29265 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -41,6 +41,7 @@
 import android.os.ServiceManager
 import android.os.UserHandle
 import android.os.UserManager
+import android.permission.flags.Flags
 import android.permission.IOnPermissionsChangeListener
 import android.permission.PermissionControllerManager
 import android.permission.PermissionManager
@@ -1409,7 +1410,7 @@
         permissionName: String,
         deviceId: Int,
     ): Int {
-        return if (deviceId == Context.DEVICE_ID_DEFAULT) {
+        return if (!Flags.deviceAwarePermissionApis() || deviceId == Context.DEVICE_ID_DEFAULT) {
             with(policy) { getPermissionFlags(appId, userId, permissionName) }
         } else {
             if (permissionName !in DevicePermissionPolicy.DEVICE_AWARE_PERMISSIONS) {
@@ -1442,7 +1443,7 @@
         deviceId: Int,
         flags: Int
     ): Boolean {
-        return if (deviceId == Context.DEVICE_ID_DEFAULT) {
+        return if (!Flags.deviceAwarePermissionApis() || deviceId == Context.DEVICE_ID_DEFAULT) {
             with(policy) {
                setPermissionFlags(appId, userId, permissionName, flags)
             }
@@ -1737,6 +1738,9 @@
             with(policy) {
                 resetRuntimePermissions(androidPackage.packageName, userId)
             }
+            with(devicePolicy) {
+                resetRuntimePermissions(androidPackage.packageName, userId)
+            }
         }
     }
 
@@ -1747,6 +1751,9 @@
                     with(policy) {
                         resetRuntimePermissions(packageState.packageName, userId)
                     }
+                    with(devicePolicy) {
+                        resetRuntimePermissions(packageState.packageName, userId)
+                    }
                 }
             }
         }
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
index e04dd68..8b9efb3 100644
--- a/services/robotests/backup/Android.bp
+++ b/services/robotests/backup/Android.bp
@@ -59,7 +59,7 @@
         "mockito-robolectric-prebuilt",
         "platform-test-annotations",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
 
     instrumentation_for: "BackupFrameworksServicesLib",
diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp
index 36446f6..ffe6dc5 100644
--- a/services/tests/InputMethodSystemServerTests/Android.bp
+++ b/services/tests/InputMethodSystemServerTests/Android.bp
@@ -44,7 +44,7 @@
         "service-permission.stubs.system_server",
         "servicestests-core-utils",
         "servicestests-utils-mockito-extended",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [
@@ -92,7 +92,7 @@
         "service-permission.stubs.system_server",
         "servicestests-core-utils",
         "servicestests-utils-mockito-extended",
-        "truth-prebuilt",
+        "truth",
         "SimpleImeTestingLib",
         "SimpleImeImsLib",
     ],
diff --git a/services/tests/PackageManager/packageinstaller/Android.bp b/services/tests/PackageManager/packageinstaller/Android.bp
index 35d754b..e8fce8e 100644
--- a/services/tests/PackageManager/packageinstaller/Android.bp
+++ b/services/tests/PackageManager/packageinstaller/Android.bp
@@ -32,7 +32,7 @@
         "androidx.test.runner",
         "junit",
         "kotlin-test",
-        "truth-prebuilt",
+        "truth",
     ],
     platform_apis: true,
     test_suites: ["device-tests"],
diff --git a/services/tests/PackageManagerComponentOverrideTests/Android.bp b/services/tests/PackageManagerComponentOverrideTests/Android.bp
index bc36970..00850a5 100644
--- a/services/tests/PackageManagerComponentOverrideTests/Android.bp
+++ b/services/tests/PackageManagerComponentOverrideTests/Android.bp
@@ -38,7 +38,7 @@
         "service-permission.stubs.system_server",
         "servicestests-utils-mockito-extended",
         "testng", // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
-        "truth-prebuilt",
+        "truth",
     ],
 
     jni_libs: [
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index 9c4e6fd..ad7af44 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -29,7 +29,7 @@
     static_libs: [
         "compatibility-device-util-axt",
         "androidx.test.runner",
-        "truth-prebuilt",
+        "truth",
         "Harrier",
     ],
     platform_apis: true,
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index ce28682..6eacef7 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -30,7 +30,7 @@
     libs: [
         "tradefed",
         "junit",
-        "truth-prebuilt",
+        "truth",
     ],
     static_libs: [
         "ApexInstallHelper",
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index 462c580..cea9c59 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -38,6 +38,6 @@
         "junit-params",
         "androidx.test.ext.junit",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
index 5718474..ed5f2b5 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
@@ -28,6 +28,6 @@
         "androidx.test.runner",
         "junit",
         "kotlin-test",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index a1d846e..3aca1ca 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -41,7 +41,7 @@
         "mockito-target-minus-junit4",
         "platform-test-annotations",
         "ShortcutManagerTestUtils",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "platformprotosnano",
         "framework-protos",
@@ -51,7 +51,7 @@
         "servicestests-utils",
         "service-permission.impl",
         "testng",
-        "truth-prebuilt",
+        "truth",
         "junit",
         "junit-params",
         "platform-compat-test-rules",
diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp
index 9b3b8c35..85059838 100644
--- a/services/tests/PackageManagerServiceTests/unit/Android.bp
+++ b/services/tests/PackageManagerServiceTests/unit/Android.bp
@@ -37,7 +37,7 @@
         "services.core",
         "servicestests-utils",
         "servicestests-core-utils",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: [
         "libdexmakerjvmtiagent",
diff --git a/services/tests/RemoteProvisioningServiceTests/Android.bp b/services/tests/RemoteProvisioningServiceTests/Android.bp
index fc2c085..19c9136 100644
--- a/services/tests/RemoteProvisioningServiceTests/Android.bp
+++ b/services/tests/RemoteProvisioningServiceTests/Android.bp
@@ -30,8 +30,8 @@
         "mockito-target",
         "service-rkp.impl",
         "services.core",
-        "truth-prebuilt",
-        "truth-java8-extension-jar",
+        "truth",
+        "truth-java8-extension",
     ],
     test_suites: [
         "device-tests",
diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp
index e724e804..9dacfea 100644
--- a/services/tests/apexsystemservices/Android.bp
+++ b/services/tests/apexsystemservices/Android.bp
@@ -34,7 +34,7 @@
         "compatibility-host-util",
         "cts-install-lib-host",
         "frameworks-base-hostutils",
-        "truth-prebuilt",
+        "truth",
         "modules-utils-build-testing",
     ],
     test_suites: [
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 6ef150c..c37d21a 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -179,6 +179,89 @@
     }
 
     @Test
+    public void testPowerThrottlingConfigFromDisplayConfig() throws IOException {
+        setupDisplayDeviceConfigFromDisplayConfigFile();
+
+        DisplayDeviceConfig.PowerThrottlingConfigData powerThrottlingConfigData =
+                mDisplayDeviceConfig.getPowerThrottlingConfigData();
+        assertNotNull(powerThrottlingConfigData);
+        assertEquals(0.1f, powerThrottlingConfigData.brightnessLowestCapAllowed, SMALL_DELTA);
+        assertEquals(10, powerThrottlingConfigData.pollingWindowMillis);
+    }
+
+    @Test
+    public void testPowerThrottlingDataFromDisplayConfig() throws IOException {
+        setupDisplayDeviceConfigFromDisplayConfigFile();
+
+        List<DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel>
+                defaultThrottlingLevels = new ArrayList<>();
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 800f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 600f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 400f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 200f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 100f
+                ));
+        defaultThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 50f
+                ));
+
+        DisplayDeviceConfig.PowerThrottlingData defaultThrottlingData =
+                new DisplayDeviceConfig.PowerThrottlingData(defaultThrottlingLevels);
+
+        List<DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel>
+                concurrentThrottlingLevels = new ArrayList<>();
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 800f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 600f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 400f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 200f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 100f
+                ));
+        concurrentThrottlingLevels.add(
+                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel(
+                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 50f
+                ));
+        DisplayDeviceConfig.PowerThrottlingData concurrentThrottlingData =
+                new DisplayDeviceConfig.PowerThrottlingData(concurrentThrottlingLevels);
+
+        HashMap<String, DisplayDeviceConfig.PowerThrottlingData> throttlingDataMap =
+                new HashMap<>(2);
+        throttlingDataMap.put("default", defaultThrottlingData);
+        throttlingDataMap.put("concurrent", concurrentThrottlingData);
+
+        assertEquals(throttlingDataMap,
+                mDisplayDeviceConfig.getPowerThrottlingDataMapByThrottlingId());
+    }
+
+    @Test
     public void testConfigValuesFromConfigResource() {
         setupDisplayDeviceConfigFromConfigResourceFile();
         verifyConfigValuesFromConfigResource();
@@ -845,6 +928,64 @@
                 +   "</screenBrightnessRampSlowIncreaseIdle>\n";
     }
 
+    private String getPowerThrottlingConfig() {
+        return  "<powerThrottlingConfig >\n"
+                +       "<brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>\n"
+                +       "<pollingWindowMillis>10</pollingWindowMillis>\n"
+                +       "<powerThrottlingMap>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>light</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>800</powerQuotaMilliWatts>\n"
+                +        "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>moderate</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>600</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>severe</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>400</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>critical</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>200</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>emergency</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>100</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>shutdown</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>50</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +       "</powerThrottlingMap>\n"
+                +       "<powerThrottlingMap id=\"concurrent\">\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>light</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>800</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>moderate</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>600</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>severe</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>400</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>critical</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>200</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>emergency</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>100</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +           "<powerThrottlingPoint>\n"
+                +               "<thermalStatus>shutdown</thermalStatus>\n"
+                +               "<powerQuotaMilliWatts>50</powerQuotaMilliWatts>\n"
+                +           "</powerThrottlingPoint>\n"
+                +       "</powerThrottlingMap>\n"
+                +   "</powerThrottlingConfig>\n";
+    }
     private String getScreenBrightnessRampCapsIdle() {
         return "<screenBrightnessRampIncreaseMaxIdleMillis>"
                 +       "4000"
@@ -915,6 +1056,7 @@
                 +            "</displayBrightnessPoint>\n"
                 +       "</displayBrightnessMapping>\n"
                 +   "</autoBrightness>\n"
+                +  getPowerThrottlingConfig()
                 +   "<highBrightnessMode enabled=\"true\">\n"
                 +       "<transitionPoint>" + BRIGHTNESS[1] + "</transitionPoint>\n"
                 +       "<minimumLux>10000</minimumLux>\n"
diff --git a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
new file mode 100644
index 0000000..5c50acb
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 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.display;
+
+import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+import android.hardware.display.DisplayManager;
+import android.testing.TestableContext;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.display.RefreshRateSettingsUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RefreshRateSettingsUtilsTest {
+
+    @Rule
+    public final TestableContext mContext = new TestableContext(
+            InstrumentationRegistry.getInstrumentation().getContext());
+
+    @Mock
+    private DisplayManager mDisplayManagerMock;
+    @Mock
+    private Display mDisplayMock;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock);
+
+        Display.Mode[] modes = new Display.Mode[]{
+                new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+                        /* refreshRate= */ 60),
+                new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+                        /* refreshRate= */ 120),
+                new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+                        /* refreshRate= */ 90)
+        };
+
+        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+        when(mDisplayMock.getSupportedModes()).thenReturn(modes);
+    }
+
+    @Test
+    public void testFindHighestRefreshRateForDefaultDisplay() {
+        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
+        assertEquals(DEFAULT_REFRESH_RATE,
+                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
+                /* delta= */ 0);
+
+        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+        assertEquals(120,
+                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
+                /* delta= */ 0);
+    }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java
index c63fac9..ee187ba 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java
@@ -22,6 +22,9 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+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.when;
 
@@ -97,6 +100,37 @@
     }
 
     @Test
+    public void testRegisterHdrListener() {
+        verify(mMockHdrInfoListener).register(mMockBinder);
+    }
+
+    @Test
+    public void testRegisterOtherHdrListenerWhenCalledWithOtherToken() {
+        IBinder otherBinder = mock(IBinder.class);
+        mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, MIN_HDR_PERCENT, otherBinder);
+
+        verify(mMockHdrInfoListener).unregister(mMockBinder);
+        verify(mMockHdrInfoListener).register(otherBinder);
+    }
+
+    @Test
+    public void testRegisterHdrListenerOnceWhenCalledWithSameToken() {
+        mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, MIN_HDR_PERCENT, mMockBinder);
+
+        verify(mMockHdrInfoListener, never()).unregister(mMockBinder);
+        verify(mMockHdrInfoListener, times(1)).register(mMockBinder);
+    }
+
+    @Test
+    public void testRegisterNotCalledIfHbmConfigIsMissing() {
+        IBinder otherBinder = mock(IBinder.class);
+        mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, -1, otherBinder);
+
+        verify(mMockHdrInfoListener).unregister(mMockBinder);
+        verify(mMockHdrInfoListener, never()).register(otherBinder);
+    }
+
+    @Test
     public void testClamper_AmbientLuxChangesAboveLimit() {
         mHdrClamper.onAmbientLuxChange(500);
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index c280349..79222c0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -23,6 +23,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -37,6 +38,7 @@
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.internal.R;
+import com.android.server.display.feature.DisplayManagerFlags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -54,6 +56,8 @@
     private Resources mMockedResources;
     @Mock
     private DisplayManagerInternal mDisplayManagerInternal;
+    @Mock
+    private DisplayManagerFlags mDisplayManagerFlagsMock;
 
     private MockitoSession mSession;
     private Resources mResources;
@@ -63,10 +67,6 @@
     @Before
     public void setUp() {
         DisplayManagerInternal displayManagerInternal = mock(DisplayManagerInternal.class);
-        mDisplayWhiteBalanceTintController =
-                new DisplayWhiteBalanceTintController(displayManagerInternal);
-        mDisplayWhiteBalanceTintController.setUp(InstrumentationRegistry.getContext(), true);
-        mDisplayWhiteBalanceTintController.setActivated(true);
 
         mSession = ExtendedMockito.mockitoSession()
                 .initMocks(this)
@@ -74,6 +74,13 @@
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
+        mDisplayWhiteBalanceTintController =
+                new DisplayWhiteBalanceTintController(displayManagerInternal,
+                        mDisplayManagerFlagsMock);
+        mDisplayWhiteBalanceTintController.setUp(InstrumentationRegistry.getContext(), true);
+        mDisplayWhiteBalanceTintController.setActivated(true);
+
+
         mResources = InstrumentationRegistry.getContext().getResources();
         // These Resources are common to all tests.
         doReturn(4000)
@@ -360,9 +367,47 @@
                 1e-6f /* tolerance */);
     }
 
+    @Test
+    public void testDisplayWhiteBalance_TransitionTimes() {
+        when(mDisplayManagerFlagsMock.isAdaptiveTone2Enabled()).thenReturn(false);
+        setUpTransitionTimes();
+        setUpTintController();
+
+        assertEquals(30L,
+                mDisplayWhiteBalanceTintController.getTransitionDurationMilliseconds(true));
+        assertEquals(30L,
+                mDisplayWhiteBalanceTintController.getTransitionDurationMilliseconds(false));
+    }
+
+    @Test
+    public void testDisplayWhiteBalance_TransitionTimesDirectional() {
+        when(mDisplayManagerFlagsMock.isAdaptiveTone2Enabled()).thenReturn(true);
+        setUpTransitionTimes();
+        setUpTintController();
+
+        assertEquals(400L,
+                mDisplayWhiteBalanceTintController.getTransitionDurationMilliseconds(true));
+        assertEquals(5000L,
+                mDisplayWhiteBalanceTintController.getTransitionDurationMilliseconds(false));
+    }
+
+
+    private void setUpTransitionTimes() {
+        doReturn(mResources.getStringArray(R.array.config_displayWhiteBalanceDisplayPrimaries))
+                .when(mMockedResources)
+                .getStringArray(R.array.config_displayWhiteBalanceDisplayPrimaries);
+        when(mMockedResources.getInteger(
+                R.integer.config_displayWhiteBalanceTransitionTime)).thenReturn(30);
+        when(mMockedResources.getInteger(
+                R.integer.config_displayWhiteBalanceTransitionTimeIncrease)).thenReturn(400);
+        when(mMockedResources.getInteger(
+                R.integer.config_displayWhiteBalanceTransitionTimeDecrease)).thenReturn(5000);
+
+    }
+
     private void setUpTintController() {
         mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController(
-                mDisplayManagerInternal);
+                mDisplayManagerInternal, mDisplayManagerFlagsMock);
         mDisplayWhiteBalanceTintController.setUp(mMockedContext, true);
         mDisplayWhiteBalanceTintController.setActivated(true);
     }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index b8c18e07..c4f72b3 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -27,6 +27,7 @@
 import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
 import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.server.display.mode.Vote.INVALID_SIZE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -85,10 +86,12 @@
 
 import com.android.internal.R;
 import com.android.internal.display.BrightnessSynchronizer;
+import com.android.internal.display.RefreshRateSettingsUtils;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.util.test.FakeSettingsProviderRule;
+import com.android.modules.utils.testing.ExtendedMockitoRule;
 import com.android.server.display.DisplayDeviceConfig;
 import com.android.server.display.TestUtils;
 import com.android.server.display.feature.DisplayManagerFlags;
@@ -106,7 +109,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
@@ -252,9 +255,15 @@
     @Mock
     private DisplayManagerFlags mDisplayManagerFlags;
 
+    @Rule
+    public final ExtendedMockitoRule mExtendedMockitoRule =
+            new ExtendedMockitoRule.Builder(this)
+                    .setStrictness(Strictness.LENIENT)
+                    .spyStatic(RefreshRateSettingsUtils.class)
+                    .build();
+
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
         mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
         final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
         when(mContext.getContentResolver()).thenReturn(resolver);
@@ -1470,6 +1479,94 @@
     }
 
     @Test
+    public void testPeakRefreshRate_FlagEnabled() {
+        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+                .thenReturn(true);
+        float highestRefreshRate = 130;
+        doReturn(highestRefreshRate).when(() ->
+                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+        Sensor lightSensor = createLightSensor();
+        SensorManager sensorManager = createMockSensorManager(lightSensor);
+        director.start(sensorManager);
+
+        setPeakRefreshRate(Float.POSITIVE_INFINITY);
+
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+                highestRefreshRate);
+    }
+
+    @Test
+    public void testPeakRefreshRate_FlagDisabled() {
+        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+                .thenReturn(false);
+        float peakRefreshRate = 130;
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+        Sensor lightSensor = createLightSensor();
+        SensorManager sensorManager = createMockSensorManager(lightSensor);
+        director.start(sensorManager);
+
+        setPeakRefreshRate(peakRefreshRate);
+
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+                peakRefreshRate);
+    }
+
+    @Test
+    public void testMinRefreshRate_FlagEnabled() {
+        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+                .thenReturn(true);
+        float highestRefreshRate = 130;
+        doReturn(highestRefreshRate).when(() ->
+                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+        Sensor lightSensor = createLightSensor();
+        SensorManager sensorManager = createMockSensorManager(lightSensor);
+        director.start(sensorManager);
+
+        setMinRefreshRate(Float.POSITIVE_INFINITY);
+
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+                Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
+                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testMinRefreshRate_FlagDisabled() {
+        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+                .thenReturn(false);
+        float minRefreshRate = 130;
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+        Sensor lightSensor = createLightSensor();
+        SensorManager sensorManager = createMockSensorManager(lightSensor);
+        director.start(sensorManager);
+
+        setMinRefreshRate(minRefreshRate);
+
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+                Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate,
+                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+    }
+
+    @Test
     public void testSensorRegistration() {
         // First, configure brightness zones or DMD won't register for sensor data.
         final FakeDeviceConfig config = mInjector.getDeviceConfig();
@@ -3167,6 +3264,13 @@
         waitForIdleSync();
     }
 
+    private void setMinRefreshRate(float fps) {
+        Settings.System.putFloat(mContext.getContentResolver(), Settings.System.MIN_REFRESH_RATE,
+                fps);
+        mInjector.notifyMinRefreshRateChanged();
+        waitForIdleSync();
+    }
+
     private static SensorManager createMockSensorManager(Sensor... sensors) {
         SensorManager sensorManager = mock(SensorManager.class);
         when(sensorManager.getSensorList(anyInt())).then((invocation) -> {
@@ -3216,6 +3320,7 @@
         private final SensorManagerInternal mSensorManagerInternal;
 
         private ContentObserver mPeakRefreshRateObserver;
+        private ContentObserver mMinRefreshRateObserver;
 
         FakesInjector() {
             this(null, null, null);
@@ -3247,6 +3352,12 @@
         }
 
         @Override
+        public void registerMinRefreshRateObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer) {
+            mMinRefreshRateObserver = observer;
+        }
+
+        @Override
         public void registerDisplayListener(DisplayListener listener, Handler handler) {}
 
         @Override
@@ -3318,5 +3429,12 @@
                         PEAK_REFRESH_RATE_URI);
             }
         }
+
+        void notifyMinRefreshRateChanged() {
+            if (mMinRefreshRateObserver != null) {
+                mMinRefreshRateObserver.dispatchChange(false /*selfChange*/,
+                        MIN_REFRESH_RATE_URI);
+            }
+        }
     }
 }
diff --git a/services/tests/inprocesstests/Android.bp b/services/tests/inprocesstests/Android.bp
index 7c237ac..086e84b 100644
--- a/services/tests/inprocesstests/Android.bp
+++ b/services/tests/inprocesstests/Android.bp
@@ -14,7 +14,7 @@
         "androidx.test.core",
         "androidx.test.rules",
         "services.core",
-        "truth-prebuilt",
+        "truth",
         "platform-test-annotations",
     ],
     test_suites: ["general-tests"],
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 101498a..063af57 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -46,6 +46,7 @@
         "androidx.test.espresso.core",
         "androidx.test.espresso.contrib",
         "androidx.test.ext.truth",
+        "flag-junit",
         "frameworks-base-testutils",
         "hamcrest-library",
         "kotlin-test",
@@ -67,7 +68,7 @@
         "servicestests-core-utils",
         "servicestests-utils-mockito-extended",
         "testables",
-        "truth-prebuilt",
+        "truth",
         // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
         "testng",
         "compatibility-device-util-axt",
diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp
index f1dc1fa..1eb9888 100644
--- a/services/tests/mockingservicestests/jni/Android.bp
+++ b/services/tests/mockingservicestests/jni/Android.bp
@@ -22,6 +22,7 @@
     srcs: [
         ":lib_cachedAppOptimizer_native",
         ":lib_gameManagerService_native",
+        ":lib_oomConnection_native",
         "onload.cpp",
     ],
 
@@ -42,6 +43,7 @@
         "libgui",
         "libhidlbase",
         "liblog",
+        "libmemevents",
         "libmeminfo",
         "libnativehelper",
         "libprocessgroup",
diff --git a/services/tests/mockingservicestests/jni/onload.cpp b/services/tests/mockingservicestests/jni/onload.cpp
index 23ccb22..fb91051 100644
--- a/services/tests/mockingservicestests/jni/onload.cpp
+++ b/services/tests/mockingservicestests/jni/onload.cpp
@@ -26,6 +26,7 @@
 namespace android {
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
 int register_android_server_app_GameManagerService(JNIEnv* env);
+int register_android_server_am_OomConnection(JNIEnv* env);
 };
 
 using namespace android;
@@ -42,6 +43,7 @@
     ALOG_ASSERT(env, "Could not retrieve the env!");
     register_android_server_am_CachedAppOptimizer(env);
     register_android_server_app_GameManagerService(env);
+    register_android_server_am_OomConnection(env);
     return JNI_VERSION_1_4;
 }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 5b1508b..be29163 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -1290,7 +1290,8 @@
     }
 
     @Test
-    public void testLightStepIdleStateIdlingTimeIncreases() {
+    public void testLightStepIdleStateIdlingTimeIncreasesExponentially() {
+        mConstants.LIGHT_IDLE_INCREASE_LINEARLY = false;
         final long maintenanceTimeMs = 60_000L;
         mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = maintenanceTimeMs;
         mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = maintenanceTimeMs;
@@ -1335,13 +1336,88 @@
                 eq(mInjector.nowElapsed + idlingTimeMs),
                 anyLong(), anyString(), any(), any(Handler.class));
 
-        for (int i = 0; i < 2; ++i) {
+        for (int i = 0; i < 10; ++i) {
             // IDLE->MAINTENANCE alarm
             mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
             alarmListener.onAlarm();
             verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
             long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs;
             idlingTimeMs *= mConstants.LIGHT_IDLE_FACTOR;
+            idlingTimeMs = Math.min(idlingTimeMs, mConstants.LIGHT_MAX_IDLE_TIMEOUT);
+            // Set MAINTENANCE->IDLE
+            alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                    eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                    eq(maintenanceExpiryTime),
+                    anyLong(), anyString(), any(), any(Handler.class));
+
+            // MAINTENANCE->IDLE alarm
+            mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+            alarmListener.onAlarm();
+            verifyLightStateConditions(LIGHT_STATE_IDLE);
+            // Set IDLE->MAINTENANCE again
+            alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                    eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                    eq(mInjector.nowElapsed + idlingTimeMs),
+                    anyLong(), anyString(), any(), any(Handler.class));
+        }
+    }
+
+    @Test
+    public void testLightStepIdleStateIdlingTimeIncreasesLinearly() {
+        mConstants.LIGHT_IDLE_INCREASE_LINEARLY = true;
+        final long maintenanceTimeMs = 60_000L;
+        mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = maintenanceTimeMs;
+        mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = maintenanceTimeMs;
+        mConstants.LIGHT_IDLE_TIMEOUT = 5 * 60_000L;
+        mConstants.LIGHT_MAX_IDLE_TIMEOUT = 30 * 60_000L;
+        mConstants.LIGHT_IDLE_FACTOR = 2f;
+        mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = 2 * 60_000L;
+
+        setNetworkConnected(true);
+        mDeviceIdleController.setJobsActive(false);
+        mDeviceIdleController.setAlarmsActive(false);
+        mDeviceIdleController.setActiveIdleOpsForTest(0);
+
+        InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = ArgumentCaptor
+                .forClass(AlarmManager.OnAlarmListener.class);
+        doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+                eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+
+        // Set state to INACTIVE.
+        mDeviceIdleController.becomeActiveLocked("testing", 0);
+        setChargingOn(false);
+        setScreenOn(false);
+        verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+        long idlingTimeMs = mConstants.LIGHT_IDLE_TIMEOUT;
+        final long idleAfterInactiveExpiryTime =
+                mInjector.nowElapsed + mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
+        alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                eq(idleAfterInactiveExpiryTime),
+                anyLong(), anyString(), any(), any(Handler.class));
+
+        final AlarmManager.OnAlarmListener alarmListener =
+                alarmListenerCaptor.getAllValues().get(0);
+
+        // INACTIVE -> IDLE alarm
+        mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+        alarmListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE);
+        alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                eq(mInjector.nowElapsed + idlingTimeMs),
+                anyLong(), anyString(), any(), any(Handler.class));
+
+        for (int i = 0; i < 10; ++i) {
+            // IDLE->MAINTENANCE alarm
+            mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+            alarmListener.onAlarm();
+            verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+            long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs;
+            idlingTimeMs += mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS;
+            idlingTimeMs = Math.min(idlingTimeMs, mConstants.LIGHT_MAX_IDLE_TIMEOUT);
             // Set MAINTENANCE->IDLE
             alarmManagerInOrder.verify(mAlarmManager).setWindow(
                     eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index 64cc397..9ba4f5b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -218,4 +218,9 @@
             assertEquals(errMsg, Thread.State.TERMINATED, getState());
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 2bc66ac..40b5458 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -1210,4 +1210,9 @@
             return returnValueForstartUserOnSecondaryDisplay;
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
index 1c0989c..9391d5b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
@@ -338,4 +338,8 @@
         }
     }
 
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index d56229c..e15942b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -1126,4 +1126,9 @@
             };
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
index 0abf46b..596a3f3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
@@ -284,4 +284,9 @@
 
         return app;
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
index 434d200..dfb8fda 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
@@ -803,4 +803,9 @@
             return mHandler;
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
index fd1b068..7ec27be 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
@@ -201,4 +201,9 @@
             return mActiveServices;
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
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 2b56ea8..bded9b4 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
@@ -34,6 +34,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.job.Flags.FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER;
 import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
 import static com.android.server.job.JobSchedulerService.RARE_INDEX;
 import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
@@ -66,6 +67,7 @@
 import android.os.Build;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.telephony.CellSignalStrength;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyCallback;
@@ -79,6 +81,7 @@
 import com.android.server.net.NetworkPolicyManagerInternal;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -107,6 +110,9 @@
     @Mock
     private PackageManager mPackageManager;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     private Constants mConstants;
 
     private FlexibilityController mFlexibilityController;
@@ -898,7 +904,8 @@
             assertTrue(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));
         }
 
-        // Metered network is only when prefetching, late, and in opportunistic quota
+        // Metered network is only when prefetching, charging*, late, and in opportunistic quota
+        // *Charging only when the flag is enabled
         {
             final Network net = mock(Network.class);
             final NetworkCapabilities caps = createCapabilitiesBuilder()
@@ -910,6 +917,8 @@
             assertFalse(controller.isSatisfied(latePrefetch, net, caps, mConstants));
             assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants));
             assertFalse(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));
+            mSetFlagsRule.disableFlags(FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER);
+            when(mService.isBatteryCharging()).thenReturn(false);
 
             when(mNetPolicyManagerInternal.getSubscriptionOpportunisticQuota(
                     any(), eq(NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS)))
@@ -918,6 +927,21 @@
             // Only relax restrictions when we at least know the estimated download bytes.
             assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants));
             assertTrue(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));
+
+            mSetFlagsRule.enableFlags(FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER);
+            when(mNetPolicyManagerInternal.getSubscriptionOpportunisticQuota(
+                    any(), eq(NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS)))
+                    .thenReturn(9876543210L);
+            assertFalse(controller.isSatisfied(latePrefetch, net, caps, mConstants));
+            // Only relax restrictions when we at least know the estimated download bytes.
+            assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants));
+            assertFalse(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));
+
+            when(mService.isBatteryCharging()).thenReturn(true);
+            assertTrue(controller.isSatisfied(latePrefetch, net, caps, mConstants));
+            // Only relax restrictions when we at least know the estimated download bytes.
+            assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants));
+            assertTrue(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));
         }
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6304270..305569e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -308,7 +308,6 @@
         addDefaultProfileAndParent();
 
         mUms.setBootUser(PROFILE_USER_ID);
-
         // Boot user not switchable so return most recently in foreground.
         assertWithMessage("getBootUser")
                 .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID);
@@ -523,6 +522,24 @@
                 .isFalse();
     }
 
+    @Test
+    public void testCreateUserWithLongName_TruncatesName() {
+        UserInfo user = mUms.createUserWithThrow(generateLongString(), USER_TYPE_FULL_SECONDARY, 0);
+        assertThat(user.name.length()).isEqualTo(500);
+        UserInfo user1 = mUms.createUserWithThrow("Test", USER_TYPE_FULL_SECONDARY, 0);
+        assertThat(user1.name.length()).isEqualTo(4);
+    }
+
+    private String generateLongString() {
+        String partialString = "Test Name Test Name Test Name Test Name Test Name Test Name Test "
+                + "Name Test Name Test Name Test Name "; //String of length 100
+        StringBuilder resultString = new StringBuilder();
+        for (int i = 0; i < 660; i++) {
+            resultString.append(partialString);
+        }
+        return resultString.toString();
+    }
+
     private void removeNonSystemUsers() {
         for (UserInfo user : mUms.getUsers(true)) {
             if (!user.getUserHandle().isSystem()) {
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index 8ab4507..18a4f00 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -16,7 +16,7 @@
         "coretests-aidl",
         "platformprotosnano",
         "junit",
-        "truth-prebuilt",
+        "truth",
         "androidx.test.runner",
         "androidx.test.ext.junit",
         "androidx.test.ext.truth",
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 20d8a5d..2ece8c7 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -2,6 +2,13 @@
 // Build FrameworksServicesTests package
 //########################################################################
 
+java_defaults {
+    name: "FrameworksServicesTests-jni-defaults",
+    jni_libs: [
+        "libservicestestjni",
+    ],
+}
+
 package {
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
@@ -13,6 +20,9 @@
 
 android_test {
     name: "FrameworksServicesTests",
+    defaults: [
+        "FrameworksServicesTests-jni-defaults",
+    ],
 
     // Include all test java files.
     srcs: [
@@ -51,7 +61,7 @@
         "mockito-target-minus-junit4",
         "platform-test-annotations",
         "ShortcutManagerTestUtils",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "androidx.test.uiautomator_uiautomator",
         "platformprotosnano",
@@ -62,7 +72,7 @@
         // TODO: remove once Android migrates to JUnit 4.12,
         // which provides assertThrows
         "testng",
-        "truth-prebuilt",
+        "truth",
         "junit",
         "junit-params",
         "ActivityContext",
diff --git a/services/tests/servicestests/jni/Android.bp b/services/tests/servicestests/jni/Android.bp
new file mode 100644
index 0000000..174beb8
--- /dev/null
+++ b/services/tests/servicestests/jni/Android.bp
@@ -0,0 +1,58 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_library_shared {
+    name: "libservicestestjni",
+
+    defaults: ["android.hardware.graphics.common-ndk_shared"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+
+    srcs: [
+        ":lib_cachedAppOptimizer_native",
+        ":lib_gameManagerService_native",
+        ":lib_oomConnection_native",
+        "onload.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/base/libs",
+        "frameworks/native/services",
+        "frameworks/native/libs/math/include",
+        "frameworks/native/libs/ui/include",
+        "system/memory/libmeminfo/include",
+    ],
+
+    shared_libs: [
+        "libandroid",
+        "libandroid_runtime",
+        "libbase",
+        "libbinder",
+        "libgralloctypes",
+        "libgui",
+        "libhidlbase",
+        "liblog",
+        "libmeminfo",
+        "libmemevents",
+        "libnativehelper",
+        "libprocessgroup",
+        "libutils",
+        "libcutils",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hidl.token@1.0-utils",
+    ],
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/jni/onload.cpp b/services/tests/servicestests/jni/onload.cpp
new file mode 100644
index 0000000..f160b3d
--- /dev/null
+++ b/services/tests/servicestests/jni/onload.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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 is a mini native libaray for cached app optimizer tests to run properly. It
+ * loads all the native methods necessary.
+ */
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+namespace android {
+int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
+int register_android_server_app_GameManagerService(JNIEnv* env);
+int register_android_server_am_OomConnection(JNIEnv* env);
+};
+
+using namespace android;
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
+{
+    JNIEnv* env = NULL;
+    jint result = -1;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        ALOGE("GetEnv failed!");
+        return result;
+    }
+    ALOG_ASSERT(env, "Could not retrieve the env!");
+    register_android_server_am_CachedAppOptimizer(env);
+    register_android_server_app_GameManagerService(env);
+    register_android_server_am_OomConnection(env);
+    return JNI_VERSION_1_4;
+}
diff --git a/services/tests/servicestests/res/xml/usertypes_test_profile.xml b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
index 0115db6..ef19ba1 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_profile.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
@@ -40,6 +40,7 @@
             mediaSharedWithParent='true'
             credentialShareableWithParent='false'
             showInSettings='23'
+            hideInSettingsInQuietMode='true'
             inheritDevicePolicy='450'
             deleteAppWithParent='false'
             alwaysVisible='true'
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
index 8a057df..0988eea 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
@@ -366,6 +366,7 @@
     private void assumeCameraTorchAvailable() {
         assumeTrue(mCameraManager != null);
         assumeTrue(!mCameraInfoMap.isEmpty());
+        assumeTrue(mCameraInfoMap.values().stream().anyMatch(info -> info.mIsValid));
     }
 
     private void simulateCallSequence() throws InterruptedException {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 430f600..caa9e7c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -1065,7 +1065,7 @@
                     mMgh.clearAndTransitionToStateDetecting();
                     break;
                 case STATE_ACTIVATED:
-                    if (mMgh.mDetectTripleTap) {
+                    if (mMgh.mDetectSingleFingerTripleTap) {
                         goFromStateIdleTo(STATE_2TAPS);
                         tap();
                     } else {
@@ -1147,7 +1147,7 @@
                 break;
             case STATE_ACTIVATED:
             case STATE_ZOOMED_OUT_FROM_SERVICE:
-                if (mMgh.mDetectTripleTap) {
+                if (mMgh.mDetectSingleFingerTripleTap) {
                     tap();
                     tap();
                     returnToNormalFrom(STATE_ACTIVATED_2TAPS);
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
index acdfee9..c0051c6 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
@@ -172,4 +172,9 @@
                 anyString(), any(), any(), any(), anyBoolean(), any(), eq(mAuxExecutorService),
                 anyBoolean(), anyBoolean(), any());
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("servicestestjni");
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
index 9fdbdda..70527ce 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
@@ -228,6 +228,7 @@
         TestHandler mTestHandler;
 
         TestInjector(int skip, boolean immediate) {
+            super(mHandler);
             mTracker = new TestTracker(skip);
             mImmediate = immediate;
         }
@@ -249,9 +250,16 @@
             return mTestHandler;
         }
 
+        @Override
         AnrTimer.CpuTracker getTracker() {
             return mTracker;
         }
+
+        /** For test purposes, always enable the feature. */
+        @Override
+        boolean getFeatureEnabled() {
+            return true;
+        }
     }
 
     // Tests
@@ -261,7 +269,6 @@
     // 4. Start a couple of timers.  Verify max active timers.  Discard one and verify the active
     //    count drops by 1.  Accept one and verify the active count drops by 1.
 
-
     @Test
     public void testSimpleTimeout() throws Exception {
         // Create an immediate TestHandler.
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 61b30a0..e8cbcf9 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -233,6 +233,7 @@
     private VirtualDeviceManagerService mVdms;
     private VirtualDeviceManagerInternal mLocalService;
     private VirtualDeviceManagerService.VirtualDeviceManagerImpl mVdm;
+    private VirtualDeviceManagerService.VirtualDeviceManagerNativeImpl mVdmNative;
     private VirtualDeviceLog mVirtualDeviceLog;
     @Mock
     private InputController.NativeWrapper mNativeWrapperMock;
@@ -340,6 +341,7 @@
         mSetFlagsRule.disableFlags(Flags.FLAG_DYNAMIC_POLICY);
         mSetFlagsRule.disableFlags(Flags.FLAG_STREAM_PERMISSIONS);
         mSetFlagsRule.disableFlags(Flags.FLAG_VDM_CUSTOM_HOME);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_NATIVE_VDM);
 
         doReturn(true).when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
         doNothing().when(mInputManagerInternalMock).setPointerAcceleration(anyFloat(), anyInt());
@@ -384,6 +386,7 @@
         mVdms = new VirtualDeviceManagerService(mContext);
         mLocalService = mVdms.getLocalServiceInstance();
         mVdm = mVdms.new VirtualDeviceManagerImpl();
+        mVdmNative = mVdms.new VirtualDeviceManagerNativeImpl();
         mVirtualDeviceLog = new VirtualDeviceLog(mContext);
         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1);
         mSensorController = mDeviceImpl.getSensorControllerForTest();
@@ -440,24 +443,32 @@
     public void getDevicePolicy_invalidDeviceId_returnsDefault() {
         assertThat(mVdm.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS))
                 .isEqualTo(DEVICE_POLICY_DEFAULT);
+        assertThat(mVdmNative.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS))
+                .isEqualTo(DEVICE_POLICY_DEFAULT);
     }
 
     @Test
     public void getDevicePolicy_defaultDeviceId_returnsDefault() {
         assertThat(mVdm.getDevicePolicy(DEVICE_ID_DEFAULT, POLICY_TYPE_SENSORS))
                 .isEqualTo(DEVICE_POLICY_DEFAULT);
+        assertThat(mVdmNative.getDevicePolicy(DEVICE_ID_DEFAULT, POLICY_TYPE_SENSORS))
+                .isEqualTo(DEVICE_POLICY_DEFAULT);
     }
 
     @Test
     public void getDevicePolicy_nonExistentDeviceId_returnsDefault() {
         assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS))
                 .isEqualTo(DEVICE_POLICY_DEFAULT);
+        assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS))
+                .isEqualTo(DEVICE_POLICY_DEFAULT);
     }
 
     @Test
     public void getDevicePolicy_unspecifiedPolicy_returnsDefault() {
         assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
                 .isEqualTo(DEVICE_POLICY_DEFAULT);
+        assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
+                .isEqualTo(DEVICE_POLICY_DEFAULT);
     }
 
     @Test
@@ -472,6 +483,8 @@
 
         assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
                 .isEqualTo(DEVICE_POLICY_CUSTOM);
+        assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
+                .isEqualTo(DEVICE_POLICY_CUSTOM);
     }
 
     @Test
@@ -567,8 +580,8 @@
 
     @Test
     public void getDeviceIdsForUid_noRunningApps_returnsNull() {
-        Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
-        assertThat(deviceIds).isEmpty();
+        assertThat(mLocalService.getDeviceIdsForUid(UID_1)).isEmpty();
+        assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).isEmpty();
     }
 
     @Test
@@ -577,8 +590,8 @@
         mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
                 Sets.newArraySet(UID_2));
 
-        Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
-        assertThat(deviceIds).isEmpty();
+        assertThat(mLocalService.getDeviceIdsForUid(UID_1)).isEmpty();
+        assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).isEmpty();
     }
 
     @Test
@@ -587,8 +600,9 @@
         mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
                 Sets.newArraySet(UID_1));
 
-        Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
-        assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId());
+        int deviceId = mDeviceImpl.getDeviceId();
+        assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId);
+        assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId);
     }
 
     @Test
@@ -598,8 +612,9 @@
         mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
                 Sets.newArraySet(UID_1, UID_2));
 
-        Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
-        assertThat(deviceIds).containsExactly(mDeviceImpl.getDeviceId());
+        int deviceId = mDeviceImpl.getDeviceId();
+        assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId);
+        assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId);
     }
 
     @Test
@@ -611,8 +626,9 @@
         secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged(
                 Sets.newArraySet(UID_1));
 
-        Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
-        assertThat(deviceIds).containsExactly(secondDevice.getDeviceId());
+        int deviceId = secondDevice.getDeviceId();
+        assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId);
+        assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId);
     }
 
     @Test
@@ -628,8 +644,9 @@
         secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged(
                 Sets.newArraySet(UID_1, UID_2));
 
-        Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
-        assertThat(deviceIds).containsExactly(
+        assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(
+                mDeviceImpl.getDeviceId(), secondDevice.getDeviceId());
+        assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(
                 mDeviceImpl.getDeviceId(), secondDevice.getDeviceId());
     }
 
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 7d73563..7dcfc88 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -284,6 +284,7 @@
         assertEquals(info.currentState, DEFAULT_DEVICE_STATE.getIdentifier());
     }
 
+    @FlakyTest(bugId = 297949293)
     @Test
     public void getDeviceStateInfo_baseStateAndCommittedStateNotSet() throws RemoteException {
         // Create a provider and a service without an initial base state.
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index 184c976..3de167e 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -336,7 +336,8 @@
             return new FontConfig(Collections.emptyList(),
                     Collections.emptyList(),
                     Collections.singletonList(new FontConfig.NamedFamilyList(
-                            Collections.singletonList(family), "sans-serif")), 0, 1);
+                            Collections.singletonList(family), "sans-serif")),
+                    Collections.emptyList(), 0, 1);
         };
 
         UpdatableFontDir dirForPreparation = new UpdatableFontDir(
@@ -499,7 +500,8 @@
                     Collections.emptyList(),
                     Collections.emptyList(),
                     Collections.singletonList(new FontConfig.NamedFamilyList(
-                            Collections.singletonList(family), "sans-serif")), 0, 1);
+                            Collections.singletonList(family), "sans-serif")),
+                    Collections.emptyList(), 0, 1);
         });
         dir.loadFontFileMap();
 
@@ -651,7 +653,8 @@
                     FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE);
             return new FontConfig(Collections.emptyList(), Collections.emptyList(),
                     Collections.singletonList(new FontConfig.NamedFamilyList(
-                            Collections.singletonList(family), "sans-serif")), 0, 1);
+                            Collections.singletonList(family), "sans-serif")),
+                    Collections.emptyList(), 0, 1);
         });
         dir.loadFontFileMap();
 
diff --git a/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java b/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java
new file mode 100644
index 0000000..949f8e7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2023 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.net;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.text.TextUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+import com.android.server.connectivity.Vpn;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LockdownVpnTrackerTest {
+    private static final NetworkCapabilities TEST_CELL_NC = new NetworkCapabilities.Builder()
+            .addTransportType(TRANSPORT_CELLULAR)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+            .build();
+    private static final LinkProperties TEST_CELL_LP = new LinkProperties();
+
+    static {
+        TEST_CELL_LP.setInterfaceName("rmnet0");
+        TEST_CELL_LP.addLinkAddress(new LinkAddress("192.0.2.2/25"));
+    }
+
+    // Use a context wrapper instead of a mock since LockdownVpnTracker builds notifications which
+    // is tedious and currently unnecessary to mock.
+    private final Context mContext = new ContextWrapper(InstrumentationRegistry.getContext()) {
+        @Override
+        public Object getSystemService(String name) {
+            if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
+            if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
+
+            return super.getSystemService(name);
+        }
+    };
+    @Mock private ConnectivityManager mCm;
+    @Mock private Vpn mVpn;
+    @Mock private NotificationManager mNotificationManager;
+    @Mock private NetworkInfo mVpnNetworkInfo;
+    @Mock private VpnConfig mVpnConfig;
+    @Mock private Network mNetwork;
+    @Mock private Network mNetwork2;
+    @Mock private Network mVpnNetwork;
+
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+    private VpnProfile mProfile;
+
+    private VpnProfile createTestVpnProfile() {
+        final String profileName = "testVpnProfile";
+        final VpnProfile profile = new VpnProfile(profileName);
+        profile.name = "My VPN";
+        profile.server = "192.0.2.1";
+        profile.dnsServers = "8.8.8.8";
+        profile.ipsecIdentifier = "My ipsecIdentifier";
+        profile.ipsecSecret = "My PSK";
+        profile.type = VpnProfile.TYPE_IKEV2_IPSEC_PSK;
+
+        return profile;
+    }
+
+    private NetworkCallback getDefaultNetworkCallback() {
+        final ArgumentCaptor<NetworkCallback> callbackCaptor =
+                ArgumentCaptor.forClass(NetworkCallback.class);
+        verify(mCm).registerSystemDefaultNetworkCallback(callbackCaptor.capture(), eq(mHandler));
+        return callbackCaptor.getValue();
+    }
+
+    private NetworkCallback getVpnNetworkCallback() {
+        final ArgumentCaptor<NetworkCallback> callbackCaptor =
+                ArgumentCaptor.forClass(NetworkCallback.class);
+        verify(mCm).registerNetworkCallback(any(), callbackCaptor.capture(), eq(mHandler));
+        return callbackCaptor.getValue();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mHandlerThread = new HandlerThread("LockdownVpnTrackerTest");
+        mHandlerThread.start();
+        mHandler = mHandlerThread.getThreadHandler();
+
+        doReturn(mVpnNetworkInfo).when(mVpn).getNetworkInfo();
+        doReturn(false).when(mVpnNetworkInfo).isConnectedOrConnecting();
+        doReturn(mVpnConfig).when(mVpn).getLegacyVpnConfig();
+        // mVpnConfig is a mock but the production code will try to add addresses in this array
+        // assuming it's non-null, so it needs to be initialized.
+        mVpnConfig.addresses = new ArrayList<>();
+
+        mProfile = createTestVpnProfile();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mHandlerThread != null) {
+            mHandlerThread.quitSafely();
+            mHandlerThread.join();
+        }
+    }
+
+    private LockdownVpnTracker initAndVerifyLockdownVpnTracker() {
+        final LockdownVpnTracker lockdownVpnTracker =
+                new LockdownVpnTracker(mContext, mHandler, mVpn, mProfile);
+        lockdownVpnTracker.init();
+        verify(mVpn).setEnableTeardown(false);
+        verify(mVpn).setLockdown(true);
+        verify(mCm).setLegacyLockdownVpnEnabled(true);
+        verify(mVpn).stopVpnRunnerPrivileged();
+        verify(mNotificationManager).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+
+        return lockdownVpnTracker;
+    }
+
+    private void callCallbacksForNetworkConnect(NetworkCallback callback, Network network,
+            NetworkCapabilities nc, LinkProperties lp, boolean blocked) {
+        callback.onAvailable(network);
+        callback.onCapabilitiesChanged(network, nc);
+        callback.onLinkPropertiesChanged(network, lp);
+        callback.onBlockedStatusChanged(network, blocked);
+    }
+
+    private void callCallbacksForNetworkConnect(NetworkCallback callback, Network network) {
+        callCallbacksForNetworkConnect(
+                callback, network, TEST_CELL_NC, TEST_CELL_LP, true /* blocked */);
+    }
+
+    private boolean isExpectedNotification(Notification notification, int titleRes, int iconRes) {
+        if (!NOTIFICATION_CHANNEL_VPN.equals(notification.getChannelId())) {
+            return false;
+        }
+        final CharSequence expectedTitle = mContext.getString(titleRes);
+        final CharSequence actualTitle = notification.extras.getCharSequence(
+                Notification.EXTRA_TITLE);
+        if (!TextUtils.equals(expectedTitle, actualTitle)) {
+            return false;
+        }
+        return notification.getSmallIcon().getResId() == iconRes;
+    }
+
+    @Test
+    public void testShutdown() {
+        final LockdownVpnTracker lockdownVpnTracker = initAndVerifyLockdownVpnTracker();
+        final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+        final NetworkCallback vpnCallback = getVpnNetworkCallback();
+        clearInvocations(mVpn, mCm, mNotificationManager);
+
+        lockdownVpnTracker.shutdown();
+        verify(mVpn).stopVpnRunnerPrivileged();
+        verify(mVpn).setLockdown(false);
+        verify(mCm).setLegacyLockdownVpnEnabled(false);
+        verify(mNotificationManager).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+        verify(mVpn).setEnableTeardown(true);
+        verify(mCm).unregisterNetworkCallback(defaultCallback);
+        verify(mCm).unregisterNetworkCallback(vpnCallback);
+    }
+
+    @Test
+    public void testDefaultNetworkConnected() {
+        initAndVerifyLockdownVpnTracker();
+        final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+        clearInvocations(mVpn, mCm, mNotificationManager);
+
+        // mNetwork connected and available.
+        callCallbacksForNetworkConnect(defaultCallback, mNetwork);
+
+        // Vpn is starting
+        verify(mVpn).startLegacyVpnPrivileged(mProfile, mNetwork, TEST_CELL_LP);
+        verify(mNotificationManager).notify(any(), eq(SystemMessage.NOTE_VPN_STATUS),
+                argThat(notification -> isExpectedNotification(notification,
+                        R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected)));
+    }
+
+    private void doTestDefaultLpChanged(LinkProperties startingLp, LinkProperties newLp) {
+        initAndVerifyLockdownVpnTracker();
+        final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+        callCallbacksForNetworkConnect(
+                defaultCallback, mNetwork, TEST_CELL_NC, startingLp, true /* blocked */);
+        clearInvocations(mVpn, mCm, mNotificationManager);
+
+        // LockdownVpnTracker#handleStateChangedLocked() is not called on the same network even if
+        // the LinkProperties change.
+        defaultCallback.onLinkPropertiesChanged(mNetwork, newLp);
+
+        // Ideally the VPN should start if it hasn't already, but it doesn't because nothing calls
+        // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
+        // TODO: consider fixing this.
+        verify(mVpn, never()).stopVpnRunnerPrivileged();
+        verify(mVpn, never()).startLegacyVpnPrivileged(any(), any(), any());
+        verify(mNotificationManager, never()).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+    }
+
+    @Test
+    public void testDefaultLPChanged_V4AddLinkAddressV4() {
+        final LinkProperties lp = new LinkProperties(TEST_CELL_LP);
+        lp.setInterfaceName("rmnet0");
+        lp.addLinkAddress(new LinkAddress("192.0.2.3/25"));
+        doTestDefaultLpChanged(TEST_CELL_LP, lp);
+    }
+
+    @Test
+    public void testDefaultLPChanged_V4AddLinkAddressV6() {
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName("rmnet0");
+        lp.addLinkAddress(new LinkAddress("192.0.2.3/25"));
+        final LinkProperties newLp = new LinkProperties(lp);
+        newLp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+        doTestDefaultLpChanged(lp, newLp);
+    }
+
+    @Test
+    public void testDefaultLPChanged_V6AddLinkAddressV4() {
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName("rmnet0");
+        lp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+        final LinkProperties newLp = new LinkProperties(lp);
+        newLp.addLinkAddress(new LinkAddress("192.0.2.3/25"));
+        doTestDefaultLpChanged(lp, newLp);
+    }
+
+    @Test
+    public void testDefaultLPChanged_AddLinkAddressV4() {
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName("rmnet0");
+        doTestDefaultLpChanged(lp, TEST_CELL_LP);
+    }
+
+    @Test
+    public void testDefaultNetworkChanged() {
+        initAndVerifyLockdownVpnTracker();
+        final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+        final NetworkCallback vpnCallback = getVpnNetworkCallback();
+        callCallbacksForNetworkConnect(defaultCallback, mNetwork);
+        clearInvocations(mVpn, mCm, mNotificationManager);
+
+        // New network and LinkProperties received
+        final NetworkCapabilities wifiNc = new NetworkCapabilities.Builder()
+                .addTransportType(TRANSPORT_WIFI)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+                .build();
+        final LinkProperties wifiLp = new LinkProperties();
+        wifiLp.setInterfaceName("wlan0");
+        callCallbacksForNetworkConnect(
+                defaultCallback, mNetwork2, wifiNc, wifiLp, true /* blocked */);
+
+        // Vpn is restarted.
+        verify(mVpn).stopVpnRunnerPrivileged();
+        verify(mVpn).startLegacyVpnPrivileged(mProfile, mNetwork2, wifiLp);
+        verify(mNotificationManager, never()).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+        verify(mNotificationManager).notify(any(), eq(SystemMessage.NOTE_VPN_STATUS),
+                argThat(notification -> isExpectedNotification(notification,
+                        R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected)));
+
+        // Vpn is Connected
+        doReturn(true).when(mVpnNetworkInfo).isConnectedOrConnecting();
+        doReturn(true).when(mVpnNetworkInfo).isConnected();
+        vpnCallback.onAvailable(mVpnNetwork);
+        verify(mNotificationManager).notify(any(), eq(SystemMessage.NOTE_VPN_STATUS),
+                argThat(notification -> isExpectedNotification(notification,
+                        R.string.vpn_lockdown_connected, R.drawable.vpn_connected)));
+
+    }
+
+    @Test
+    public void testSystemDefaultLost() {
+        initAndVerifyLockdownVpnTracker();
+        final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+        // mNetwork connected
+        callCallbacksForNetworkConnect(defaultCallback, mNetwork);
+        clearInvocations(mVpn, mCm, mNotificationManager);
+
+        defaultCallback.onLost(mNetwork);
+
+        // Vpn is stopped
+        verify(mVpn).stopVpnRunnerPrivileged();
+        verify(mNotificationManager).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index 9f75cf8..253592c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -43,6 +43,7 @@
 import android.app.PropertyInvalidatedCache;
 import android.content.pm.UserInfo;
 import android.content.pm.UserInfo.UserInfoFlag;
+import android.multiuser.Flags;
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.UserHandle;
@@ -124,18 +125,34 @@
 
         mUserManagerService.putUserInfo(data.info);
 
-        // Set a global and user restriction so they get written out to the user file.
+        //Local restrictions are written to the user specific files and global restrictions
+        // are written to the SYSTEM user file.
         setUserRestrictions(data.info.id, globalRestriction, localRestriction, true);
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         DataOutputStream out = new DataOutputStream(baos);
         mUserManagerService.writeUserLP(data, out);
-        byte[] bytes = baos.toByteArray();
+        byte[] secondaryUserBytes = baos.toByteArray();
+        baos.reset();
+
+        byte[] systemUserBytes = new byte[0];
+        if (Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) {
+            UserData systemUserData = new UserData();
+            systemUserData.info = mUserManagerService.getUserInfo(UserHandle.USER_SYSTEM);
+            mUserManagerService.writeUserLP(systemUserData, baos);
+            systemUserBytes = baos.toByteArray();
+        }
 
         // Clear the restrictions to see if they are properly read in from the user file.
         setUserRestrictions(data.info.id, globalRestriction, localRestriction, false);
 
-        mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(bytes));
+        //read the secondary and SYSTEM user file to fetch local/global device policy restrictions.
+        mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(secondaryUserBytes));
+        if (Flags.saveGlobalAndGuestRestrictionsOnSystemUserXmlReadOnly()) {
+            mUserManagerService.readUserLP(UserHandle.USER_SYSTEM,
+                    new ByteArrayInputStream(systemUserBytes));
+        }
+
         assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(globalRestriction));
         assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(localRestriction));
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index a54bc91..c684a7b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -60,6 +60,7 @@
                 .setShowInLauncher(21)
                 .setStartWithParent(false)
                 .setShowInSettings(45)
+                .setHideInSettingsInQuietMode(false)
                 .setInheritDevicePolicy(67)
                 .setUseParentsContacts(false)
                 .setCrossProfileIntentFilterAccessControl(10)
@@ -72,6 +73,7 @@
         final UserProperties actualProps = new UserProperties(defaultProps);
         actualProps.setShowInLauncher(14);
         actualProps.setShowInSettings(32);
+        actualProps.setHideInSettingsInQuietMode(true);
         actualProps.setInheritDevicePolicy(51);
         actualProps.setUseParentsContacts(true);
         actualProps.setCrossProfileIntentFilterAccessControl(20);
@@ -228,6 +230,8 @@
         assertThat(expected.getShowInLauncher()).isEqualTo(actual.getShowInLauncher());
         assertThat(expected.getStartWithParent()).isEqualTo(actual.getStartWithParent());
         assertThat(expected.getShowInSettings()).isEqualTo(actual.getShowInSettings());
+        assertThat(expected.getHideInSettingsInQuietMode())
+                .isEqualTo(actual.getHideInSettingsInQuietMode());
         assertThat(expected.getInheritDevicePolicy()).isEqualTo(actual.getInheritDevicePolicy());
         assertThat(expected.getUseParentsContacts()).isEqualTo(actual.getUseParentsContacts());
         assertThat(expected.getCrossProfileIntentFilterAccessControl())
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index e3579b4..20270a8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -90,6 +90,7 @@
                 .setMediaSharedWithParent(true)
                 .setCredentialShareableWithParent(false)
                 .setShowInSettings(900)
+                .setHideInSettingsInQuietMode(true)
                 .setInheritDevicePolicy(340)
                 .setDeleteAppWithParent(true)
                 .setAlwaysVisible(true);
@@ -160,6 +161,7 @@
         assertTrue(type.getDefaultUserPropertiesReference().isMediaSharedWithParent());
         assertFalse(type.getDefaultUserPropertiesReference().isCredentialShareableWithParent());
         assertEquals(900, type.getDefaultUserPropertiesReference().getShowInSettings());
+        assertTrue(type.getDefaultUserPropertiesReference().getHideInSettingsInQuietMode());
         assertEquals(340, type.getDefaultUserPropertiesReference()
                 .getInheritDevicePolicy());
         assertTrue(type.getDefaultUserPropertiesReference().getDeleteAppWithParent());
@@ -217,6 +219,7 @@
         assertFalse(props.isCredentialShareableWithParent());
         assertFalse(props.getDeleteAppWithParent());
         assertFalse(props.getAlwaysVisible());
+        assertFalse(props.getHideInSettingsInQuietMode());
 
         assertFalse(type.hasBadge());
     }
@@ -304,6 +307,7 @@
                 .setMediaSharedWithParent(false)
                 .setCredentialShareableWithParent(true)
                 .setShowInSettings(20)
+                .setHideInSettingsInQuietMode(false)
                 .setInheritDevicePolicy(21)
                 .setDeleteAppWithParent(true)
                 .setAlwaysVisible(false);
@@ -344,6 +348,7 @@
         assertTrue(aospType.getDefaultUserPropertiesReference()
                 .isCredentialShareableWithParent());
         assertEquals(20, aospType.getDefaultUserPropertiesReference().getShowInSettings());
+        assertFalse(aospType.getDefaultUserPropertiesReference().getHideInSettingsInQuietMode());
         assertEquals(21, aospType.getDefaultUserPropertiesReference()
                 .getInheritDevicePolicy());
         assertTrue(aospType.getDefaultUserPropertiesReference().getDeleteAppWithParent());
@@ -390,6 +395,7 @@
         assertFalse(aospType.getDefaultUserPropertiesReference()
                 .isCredentialShareableWithParent());
         assertEquals(23, aospType.getDefaultUserPropertiesReference().getShowInSettings());
+        assertTrue(aospType.getDefaultUserPropertiesReference().getHideInSettingsInQuietMode());
         assertEquals(450, aospType.getDefaultUserPropertiesReference()
                 .getInheritDevicePolicy());
         assertFalse(aospType.getDefaultUserPropertiesReference().getDeleteAppWithParent());
diff --git a/services/tests/servicestests/src/com/android/server/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
index 6165260..d64cbcd 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
@@ -1,2 +1,2 @@
-# Bug component: 24949
+# Bug component: 847766
 include /services/core/java/com/android/server/timezone/OWNERS
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 2dacda0..8891413 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -31,6 +31,7 @@
         "androidx.test.rules",
         "hamcrest-library",
         "mockito-target-inline-minus-junit4",
+        "platform-compat-test-rules",
         "platform-test-annotations",
         "platformprotosnano",
         "statsdprotolite",
@@ -38,10 +39,12 @@
         "hamcrest-library",
         "servicestests-utils",
         "testables",
-        "truth-prebuilt",
+        "truth",
         // TODO: remove once Android migrates to JUnit 4.12,
         // which provides assertThrows
         "testng",
+        "flag-junit",
+        "notification_flags_lib",
     ],
 
     libs: [
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 9742384..42ad73a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -32,6 +32,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
@@ -147,6 +148,7 @@
     private static final int CUSTOM_LIGHT_ON = 10000;
     private static final int CUSTOM_LIGHT_OFF = 10000;
     private static final int MAX_VIBRATION_DELAY = 1000;
+    private static final float DEFAULT_VOLUME = 1.0f;
 
     @Before
     public void setUp() throws Exception {
@@ -397,19 +399,22 @@
     //
 
     private void verifyNeverBeep() throws RemoteException {
-        verify(mRingtonePlayer, never()).playAsync(any(), any(), anyBoolean(), any());
+        verify(mRingtonePlayer, never()).playAsync(any(), any(), anyBoolean(), any(), anyFloat());
     }
 
     private void verifyBeepUnlooped() throws RemoteException  {
-        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(false), any());
+        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(false), any(),
+                eq(DEFAULT_VOLUME));
     }
 
     private void verifyBeepLooped() throws RemoteException  {
-        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(true), any());
+        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(true), any(),
+                eq(DEFAULT_VOLUME));
     }
 
     private void verifyBeep(int times)  throws RemoteException  {
-        verify(mRingtonePlayer, times(times)).playAsync(any(), any(), anyBoolean(), any());
+        verify(mRingtonePlayer, times(times)).playAsync(any(), any(), anyBoolean(), any(),
+                eq(DEFAULT_VOLUME));
     }
 
     private void verifyNeverStopAudio() throws RemoteException {
@@ -905,7 +910,7 @@
         verifyDelayedVibrate(
                 mService.getVibratorHelper().createFallbackVibration(/* insistent= */ false));
         verify(mRingtonePlayer, never()).playAsync
-                (anyObject(), anyObject(), anyBoolean(), anyObject());
+                (anyObject(), anyObject(), anyBoolean(), anyObject(), anyFloat());
         assertTrue(r.isInterruptive());
         assertNotEquals(-1, r.getLastAudiblyAlertedMs());
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
index 81867df..9bd938f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -57,6 +57,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.media.AudioAttributes;
@@ -66,9 +67,11 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
@@ -87,8 +90,11 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LogicalLight;
 import com.android.server.pm.PackageManagerService;
+
+import java.util.List;
 import java.util.Objects;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -102,6 +108,8 @@
 @RunWith(AndroidJUnit4.class)
 @SuppressLint("GuardedBy")
 public class NotificationAttentionHelperTest extends UiServiceTestCase {
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Mock AudioManager mAudioManager;
     @Mock Vibrator mVibrator;
@@ -115,6 +123,8 @@
     IAccessibilityManager mAccessibilityService;
     @Mock
     KeyguardManager mKeyguardManager;
+    @Mock
+    private UserManager mUserManager;
     NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
     private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
         1 << 30);
@@ -134,6 +144,8 @@
     private AccessibilityManager mAccessibilityManager;
     private static final NotificationAttentionHelper.Signals DEFAULT_SIGNALS =
         new NotificationAttentionHelper.Signals(false, 0);
+    private static final NotificationAttentionHelper.Signals WORK_PROFILE_SIGNALS =
+            new NotificationAttentionHelper.Signals(true, 0);
 
     private VibrateRepeatMatcher mVibrateOnceMatcher = new VibrateRepeatMatcher(-1);
     private VibrateRepeatMatcher mVibrateLoopMatcher = new VibrateRepeatMatcher(0);
@@ -151,6 +163,7 @@
     private static final int CUSTOM_LIGHT_ON = 10000;
     private static final int CUSTOM_LIGHT_OFF = 10000;
     private static final int MAX_VIBRATION_DELAY = 1000;
+    private static final float DEFAULT_VOLUME = 1.0f;
 
     @Before
     public void setUp() throws Exception {
@@ -178,6 +191,8 @@
 
         // TODO (b/291907312): remove feature flag
         mTestFlagResolver.setFlagOverride(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR, true);
+        // Disable feature flags by default. Tests should enable as needed.
+        mSetFlagsRule.disableFlags(Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_EXPIRE_BITMAPS);
 
         mService = spy(new NotificationManagerService(getContext(), mNotificationRecordLogger,
             mNotificationInstanceIdSequence));
@@ -189,9 +204,9 @@
 
     private void initAttentionHelper(TestableFlagResolver flagResolver) {
         mAttentionHelper = new NotificationAttentionHelper(getContext(), mock(LightsManager.class),
-            mAccessibilityManager, getContext().getPackageManager(), mUsageStats,
+            mAccessibilityManager, getContext().getPackageManager(), mUserManager, mUsageStats,
             mService.mNotificationManagerPrivate, mock(ZenModeHelper.class), flagResolver);
-        mAttentionHelper.setVibratorHelper(new VibratorHelper(getContext()));
+        mAttentionHelper.setVibratorHelper(spy(new VibratorHelper(getContext())));
         mAttentionHelper.setAudioManager(mAudioManager);
         mAttentionHelper.setSystemReady(true);
         mAttentionHelper.setLights(mLight);
@@ -282,6 +297,11 @@
             true /* noisy */, true /* buzzy*/, false /* lights */);
     }
 
+    private NotificationRecord getBuzzyBeepyNotification(UserHandle userHandle) {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                true /* noisy */, true /* buzzy*/, false /* lights */, userHandle);
+    }
+
     private NotificationRecord getLightsNotification() {
         return getNotificationRecord(mId, false /* insistent */, false /* once */,
             false /* noisy */, false /* buzzy*/, true /* lights */);
@@ -312,7 +332,13 @@
     private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
         boolean noisy, boolean buzzy, boolean lights) {
         return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, buzzy, noisy,
-            lights, null, Notification.GROUP_ALERT_ALL, false);
+            lights, null, Notification.GROUP_ALERT_ALL, false, mUser);
+    }
+
+    private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
+            boolean noisy, boolean buzzy, boolean lights, UserHandle userHandle) {
+        return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, buzzy, noisy,
+                lights, null, Notification.GROUP_ALERT_ALL, false, userHandle);
     }
 
     private NotificationRecord getLeanbackNotificationRecord(int id, boolean insistent,
@@ -320,25 +346,25 @@
         boolean noisy, boolean buzzy, boolean lights) {
         return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true,
             true,
-            null, Notification.GROUP_ALERT_ALL, true);
+            null, Notification.GROUP_ALERT_ALL, true, mUser);
     }
 
     private NotificationRecord getBeepyNotificationRecord(String groupKey, int groupAlertBehavior) {
         return getNotificationRecord(mId, false, false, true, false, false, true, true, true,
-            groupKey, groupAlertBehavior, false);
+            groupKey, groupAlertBehavior, false, mUser);
     }
 
     private NotificationRecord getLightsNotificationRecord(String groupKey,
         int groupAlertBehavior) {
         return getNotificationRecord(mId, false, false, false, false, true /*lights*/, true,
-            true, true, groupKey, groupAlertBehavior, false);
+            true, true, groupKey, groupAlertBehavior, false, mUser);
     }
 
     private NotificationRecord getNotificationRecord(int id,
         boolean insistent, boolean once,
         boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration,
         boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior,
-        boolean isLeanback) {
+        boolean isLeanback, UserHandle userHandle) {
 
         final Builder builder = new Builder(getContext())
             .setContentTitle("foo")
@@ -399,7 +425,7 @@
             .thenReturn(isLeanback);
 
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
-            mPid, n, mUser, null, System.currentTimeMillis());
+            mPid, n, userHandle, null, System.currentTimeMillis());
         NotificationRecord r = new NotificationRecord(context, sbn, mChannel);
         mService.addNotification(r);
         return r;
@@ -410,19 +436,26 @@
     //
 
     private void verifyNeverBeep() throws RemoteException {
-        verify(mRingtonePlayer, never()).playAsync(any(), any(), anyBoolean(), any());
+        verify(mRingtonePlayer, never()).playAsync(any(), any(), anyBoolean(), any(), anyFloat());
     }
 
     private void verifyBeepUnlooped() throws RemoteException  {
-        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(false), any());
+        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(false), any(),
+                eq(DEFAULT_VOLUME));
     }
 
     private void verifyBeepLooped() throws RemoteException  {
-        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(true), any());
+        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(true), any(),
+                eq(DEFAULT_VOLUME));
     }
 
     private void verifyBeep(int times)  throws RemoteException  {
-        verify(mRingtonePlayer, times(times)).playAsync(any(), any(), anyBoolean(), any());
+        verify(mRingtonePlayer, times(times)).playAsync(any(), any(), anyBoolean(), any(),
+                eq(DEFAULT_VOLUME));
+    }
+
+    private void verifyBeepVolume(float volume)  throws RemoteException  {
+        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), anyBoolean(), any(), eq(volume));
     }
 
     private void verifyNeverStopAudio() throws RemoteException {
@@ -921,7 +954,7 @@
             mAttentionHelper.getVibratorHelper().createFallbackVibration(
                 /* insistent= */ false));
         verify(mRingtonePlayer, never()).playAsync(anyObject(), anyObject(), anyBoolean(),
-            anyObject());
+            anyObject(), anyFloat());
         assertTrue(r.isInterruptive());
         assertNotEquals(-1, r.getLastAudiblyAlertedMs());
     }
@@ -1948,6 +1981,259 @@
         assertEquals(-1, r.getLastAudiblyAlertedMs());
     }
 
+    // TODO b/270456865: Only one of the two strategies will be released.
+    //  The other one need to be removed
+    @Test
+    public void testBeepVolume_politeNotif() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_COOLDOWN_RULE, "rule1");
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+        initAttentionHelper(flagResolver);
+
+        NotificationRecord r = getBeepyNotification();
+
+        // set up internal state
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should beep at 50% volume
+        r.isUpdate = true;
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        verifyBeepVolume(0.5f);
+
+        // 2nd update should beep at 0% volume
+        Mockito.reset(mRingtonePlayer);
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        verifyBeepVolume(0.0f);
+
+        verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt());
+        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
+    }
+
+    // TODO b/270456865: Only one of the two strategies will be released.
+    //  The other one need to be removed
+    @Test
+    public void testBeepVolume_politeNotif_Strategy2() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_COOLDOWN_RULE, "rule2");
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+        initAttentionHelper(flagResolver);
+
+        NotificationRecord r = getBeepyNotification();
+
+        // set up internal state
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should beep at 0% volume
+        r.isUpdate = true;
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        verifyBeepVolume(0.0f);
+
+        // 2nd update should beep at 50% volume
+        Mockito.reset(mRingtonePlayer);
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        verifyBeepVolume(0.5f);
+
+        verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt());
+        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
+    }
+
+    @Test
+    public void testVibrationIntensity_politeNotif() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_COOLDOWN_RULE, "rule1");
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+        initAttentionHelper(flagResolver);
+
+        NotificationRecord r = getBuzzyBeepyNotification();
+
+        // set up internal state
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+
+        VibratorHelper vibratorHelper = mAttentionHelper.getVibratorHelper();
+        Mockito.reset(vibratorHelper);
+
+        // update should buzz at 50% intensity
+        r.isUpdate = true;
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+
+        verify(vibratorHelper, times(1)).scale(any(), eq(0.5f));
+        Mockito.reset(vibratorHelper);
+
+        // 2nd update should buzz at 0% intensity
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        verify(vibratorHelper, times(1)).scale(any(), eq(0.0f));
+    }
+
+    @Test
+    public void testVibrationIntensity_politeNotif_Strategy2() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_COOLDOWN_RULE, "rule2");
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+        initAttentionHelper(flagResolver);
+
+        NotificationRecord r = getBuzzyBeepyNotification();
+
+        // set up internal state
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+
+        VibratorHelper vibratorHelper = mAttentionHelper.getVibratorHelper();
+        Mockito.reset(vibratorHelper);
+
+        // update should buzz at 0% intensity
+        r.isUpdate = true;
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+
+        verify(vibratorHelper, times(1)).scale(any(), eq(0.0f));
+        Mockito.reset(vibratorHelper);
+
+        // 2nd update should buzz at 50% intensity
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        verify(vibratorHelper, times(1)).scale(any(), eq(0.5f));
+    }
+
+    @Test
+    public void testBuzzOnlyOnScreenUnlock_politeNotif() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+
+        // When NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED setting is enabled
+        Settings.System.putInt(getContext().getContentResolver(),
+                Settings.System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED, 1);
+
+        initAttentionHelper(flagResolver);
+        // And screen is unlocked
+        mAttentionHelper.setUserPresent(true);
+
+        NotificationRecord r = getBuzzyBeepyNotification();
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+
+        // The notification attention should only buzz
+        verifyNeverBeep();
+        verifyVibrate();
+        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
+    }
+
+    @Test
+    public void testBeepVolume_politeNotif_disabled() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+
+        // When NOTIFICATION_COOLDOWN_ENABLED setting is disabled
+        Settings.System.putInt(getContext().getContentResolver(),
+                Settings.System.NOTIFICATION_COOLDOWN_ENABLED, 0);
+
+        initAttentionHelper(flagResolver);
+
+        NotificationRecord r = getBeepyNotification();
+
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should beep at 100% volume
+        r.isUpdate = true;
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        verifyBeepVolume(1.0f);
+
+        // 2nd update should beep at 100% volume
+        Mockito.reset(mRingtonePlayer);
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        verifyBeepVolume(1.0f);
+
+        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
+    }
+
+    @Test
+    public void testBeepVolume_politeNotif_workProfile() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_COOLDOWN_RULE, "rule1");
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+
+        final int workProfileUserId = mUser.getIdentifier() + 1;
+
+        // Enable notifications cooldown for work profile
+        Settings.System.putIntForUser(getContext().getContentResolver(),
+                Settings.System.NOTIFICATION_COOLDOWN_ENABLED, 1, workProfileUserId);
+
+        when(mUserManager.getProfiles(mUser.getIdentifier())).thenReturn(
+                List.of(new UserInfo(workProfileUserId, "work_profile", null,
+                        UserInfo.FLAG_PROFILE | UserInfo.FLAG_MANAGED_PROFILE,
+                        UserInfo.getDefaultUserType(UserInfo.FLAG_MANAGED_PROFILE))));
+
+        initAttentionHelper(flagResolver);
+
+        final NotificationRecord r = getBuzzyBeepyNotification(UserHandle.of(workProfileUserId));
+
+        // set up internal state
+        mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should beep at 50% volume
+        r.isUpdate = true;
+        mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS);
+        verifyBeepVolume(0.5f);
+
+        // 2nd update should beep at 0% volume
+        Mockito.reset(mRingtonePlayer);
+        mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS);
+        verifyBeepVolume(0.0f);
+
+        verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt());
+        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
+    }
+
+    @Test
+    public void testBeepVolume_politeNotif_workProfile_disabled() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_COOLDOWN_RULE, "rule1");
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50);
+        flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0);
+
+        final int workProfileUserId = mUser.getIdentifier() + 1;
+
+        // Disable notifications cooldown for work profile
+        Settings.System.putIntForUser(getContext().getContentResolver(),
+                Settings.System.NOTIFICATION_COOLDOWN_ENABLED, 0, workProfileUserId);
+
+        when(mUserManager.getProfiles(mUser.getIdentifier())).thenReturn(
+                List.of(new UserInfo(workProfileUserId, "work_profile", null,
+                        UserInfo.FLAG_PROFILE | UserInfo.FLAG_MANAGED_PROFILE,
+                        UserInfo.getDefaultUserType(UserInfo.FLAG_MANAGED_PROFILE))));
+
+        initAttentionHelper(flagResolver);
+
+        final NotificationRecord r = getBuzzyBeepyNotification(UserHandle.of(workProfileUserId));
+
+        mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should beep at 100% volume
+        r.isUpdate = true;
+        mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS);
+        verifyBeepVolume(1.0f);
+
+        // 2nd update should beep at 100% volume
+        Mockito.reset(mRingtonePlayer);
+        mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS);
+        verifyBeepVolume(1.0f);
+
+        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
+    }
+
     static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
         private final int mRepeatIndex;
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java
index 312057ee..348d1bf 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java
@@ -44,6 +44,12 @@
 import org.mockito.Mock;
 
 import java.lang.reflect.Field;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZonedDateTime;
+import java.time.ZoneId;
 
 @RunWith(AndroidTestingRunner.class)
 public class NotificationBitmapJobServiceTest extends UiServiceTestCase {
@@ -103,17 +109,39 @@
 
     @Test
     public void testGetTimeUntilRemoval_beforeToday2am_returnTimeUntilToday2am() {
-        final long timeUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ 1,
-                /* today2AM= */ 2, /* tomorrow2AM= */ 26);
+        ZoneId zoneId = ZoneId.systemDefault();
+        ZonedDateTime now = Instant.now().atZone(zoneId);
+        LocalDate today = now.toLocalDate();
 
-        assertThat(timeUntilRemoval).isEqualTo(1);
+        LocalTime oneAM = LocalTime.of(/* hour= */ 1, /* minute= */ 0);
+        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0);
+
+        ZonedDateTime today1AM = ZonedDateTime.of(today, oneAM, zoneId);
+        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId);
+        ZonedDateTime tomorrow2AM = today2AM.plusDays(1);
+
+        final long msUntilRemoval = mJobService.getTimeUntilRemoval(
+                /* now= */ today1AM, today2AM, tomorrow2AM);
+
+        assertThat(msUntilRemoval).isEqualTo(Duration.ofHours(1).toMillis());
     }
 
     @Test
     public void testGetTimeUntilRemoval_afterToday2am_returnTimeUntilTomorrow2am() {
-        final long timeUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ 3,
-                /* today2AM= */ 2, /* tomorrow2AM= */ 26);
+        ZoneId zoneId = ZoneId.systemDefault();
+        ZonedDateTime now = Instant.now().atZone(zoneId);
+        LocalDate today = now.toLocalDate();
 
-        assertThat(timeUntilRemoval).isEqualTo(23);
+        LocalTime threeAM = LocalTime.of(/* hour= */ 3, /* minute= */ 0);
+        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0);
+
+        ZonedDateTime today3AM = ZonedDateTime.of(today, threeAM, zoneId);
+        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId);
+        ZonedDateTime tomorrow2AM = today2AM.plusDays(1);
+
+        final long msUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ today3AM,
+                today2AM, tomorrow2AM);
+
+        assertThat(msUntilRemoval).isEqualTo(Duration.ofHours(23).toMillis());
     }
 }
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
index d758e71..3499a12 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
@@ -71,10 +71,10 @@
     @Before
     public void setUp() throws Exception {
         mJobService = new NotificationHistoryJobService();
+        mJobService.attachBaseContext(mContext);
+        mJobService.onCreate();
+        mJobService.onBind(/* intent= */ null);  // Create JobServiceEngine within JobService.
 
-        final Field field = JobService.class.getDeclaredField("mEngine");
-        field.setAccessible(true);
-        field.set(mJobService, mock(JobServiceEngine.class));
         mContext.addMockSystemService(JobScheduler.class, mMockJobScheduler);
 
         // add NotificationManagerInternal to LocalServices
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index 7a55143..53ca704 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -23,9 +23,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
@@ -49,12 +47,10 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
-import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
@@ -158,81 +154,6 @@
         }
     }
 
-    // Tests parceling of NotificationRankingUpdate, and by extension, RankingMap and Ranking.
-    @Test
-    public void testRankingUpdate_parcel() {
-        NotificationRankingUpdate nru = generateUpdate();
-        Parcel parcel = Parcel.obtain();
-        nru.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        NotificationRankingUpdate nru1 = NotificationRankingUpdate.CREATOR.createFromParcel(parcel);
-        assertEquals(nru, nru1);
-    }
-
-    // Tests parceling of RankingMap and RankingMap.equals
-    @Test
-    public void testRankingMap_parcel() {
-        RankingMap rmap = generateUpdate().getRankingMap();
-        Parcel parcel = Parcel.obtain();
-        rmap.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        RankingMap rmap1 = RankingMap.CREATOR.createFromParcel(parcel);
-
-        detailedAssertEquals(rmap, rmap1);
-        assertEquals(rmap, rmap1);
-    }
-
-    // Tests parceling of Ranking and Ranking.equals
-    @Test
-    public void testRanking_parcel() {
-        Ranking ranking = generateUpdate().getRankingMap().getRawRankingObject(mKeys[0]);
-        Parcel parcel = Parcel.obtain();
-        ranking.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        Ranking ranking1 = new Ranking(parcel);
-        detailedAssertEquals("rankings differ: ", ranking, ranking1);
-        assertEquals(ranking, ranking1);
-    }
-
-    // Tests NotificationRankingUpdate.equals(), and by extension, RankingMap and Ranking.
-    @Test
-    public void testRankingUpdate_equals() {
-        NotificationRankingUpdate nru = generateUpdate();
-        NotificationRankingUpdate nru2 = generateUpdate();
-        detailedAssertEquals(nru, nru2);
-        assertEquals(nru, nru2);
-        Ranking tweak = nru2.getRankingMap().getRawRankingObject(mKeys[0]);
-        tweak.populate(
-                tweak.getKey(),
-                tweak.getRank(),
-                !tweak.matchesInterruptionFilter(), // note the inversion here!
-                tweak.getLockscreenVisibilityOverride(),
-                tweak.getSuppressedVisualEffects(),
-                tweak.getImportance(),
-                tweak.getImportanceExplanation(),
-                tweak.getOverrideGroupKey(),
-                tweak.getChannel(),
-                (ArrayList) tweak.getAdditionalPeople(),
-                (ArrayList) tweak.getSnoozeCriteria(),
-                tweak.canShowBadge(),
-                tweak.getUserSentiment(),
-                tweak.isSuspended(),
-                tweak.getLastAudiblyAlertedMillis(),
-                tweak.isNoisy(),
-                (ArrayList) tweak.getSmartActions(),
-                (ArrayList) tweak.getSmartReplies(),
-                tweak.canBubble(),
-                tweak.isTextChanged(),
-                tweak.isConversation(),
-                tweak.getConversationShortcutInfo(),
-                tweak.getRankingAdjustment(),
-                tweak.isBubble(),
-                tweak.getProposedImportance(),
-                tweak.hasSensitiveContent()
-        );
-        assertNotEquals(nru, nru2);
-    }
-
     @Test
     public void testLegacyIcons_preM() {
         TestListenerService service = new TestListenerService();
@@ -275,7 +196,6 @@
         assertNull(n.largeIcon);
     }
 
-
     // Test data
 
     private String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"};
@@ -461,48 +381,6 @@
         }
     }
 
-    private void detailedAssertEquals(NotificationRankingUpdate a, NotificationRankingUpdate b) {
-        assertEquals(a.getRankingMap(), b.getRankingMap());
-    }
-
-    private void detailedAssertEquals(String comment, Ranking a, Ranking b) {
-        assertEquals(comment, a.getKey(), b.getKey());
-        assertEquals(comment, a.getRank(), b.getRank());
-        assertEquals(comment, a.matchesInterruptionFilter(), b.matchesInterruptionFilter());
-        assertEquals(comment, a.getLockscreenVisibilityOverride(), b.getLockscreenVisibilityOverride());
-        assertEquals(comment, a.getSuppressedVisualEffects(), b.getSuppressedVisualEffects());
-        assertEquals(comment, a.getImportance(), b.getImportance());
-        assertEquals(comment, a.getImportanceExplanation(), b.getImportanceExplanation());
-        assertEquals(comment, a.getOverrideGroupKey(), b.getOverrideGroupKey());
-        assertEquals(comment, a.getChannel(), b.getChannel());
-        assertEquals(comment, a.getAdditionalPeople(), b.getAdditionalPeople());
-        assertEquals(comment, a.getSnoozeCriteria(), b.getSnoozeCriteria());
-        assertEquals(comment, a.canShowBadge(), b.canShowBadge());
-        assertEquals(comment, a.getUserSentiment(), b.getUserSentiment());
-        assertEquals(comment, a.isSuspended(), b.isSuspended());
-        assertEquals(comment, a.getLastAudiblyAlertedMillis(), b.getLastAudiblyAlertedMillis());
-        assertEquals(comment, a.isNoisy(), b.isNoisy());
-        assertEquals(comment, a.getSmartReplies(), b.getSmartReplies());
-        assertEquals(comment, a.canBubble(), b.canBubble());
-        assertEquals(comment, a.isConversation(), b.isConversation());
-        assertEquals(comment, a.getConversationShortcutInfo().getId(),
-                b.getConversationShortcutInfo().getId());
-        assertActionsEqual(a.getSmartActions(), b.getSmartActions());
-        assertEquals(a.getProposedImportance(), b.getProposedImportance());
-        assertEquals(a.hasSensitiveContent(), b.hasSensitiveContent());
-    }
-
-    private void detailedAssertEquals(RankingMap a, RankingMap b) {
-        Ranking arank = new Ranking();
-        Ranking brank = new Ranking();
-        assertArrayEquals(a.getOrderedKeys(), b.getOrderedKeys());
-        for (String key : a.getOrderedKeys()) {
-            a.getRanking(key, arank);
-            b.getRanking(key, brank);
-            detailedAssertEquals("ranking for key <" + key + ">", arank, brank);
-        }
-    }
-
     public static class TestListenerService extends NotificationListenerService {
         private final IBinder binder = new LocalBinder();
         public int targetSdk = 0;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9543a2d..3d4b4a6 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -91,7 +91,7 @@
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
-import static com.android.server.notification.NotificationManagerService.BITMAP_EXPIRATION_TIME_MS;
+import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION;
 import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
@@ -164,6 +164,7 @@
 import android.app.usage.UsageStatsManagerInternal;
 import android.companion.AssociationInfo;
 import android.companion.ICompanionDeviceManager;
+import android.compat.testing.PlatformCompatChangeRule;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentUris;
@@ -270,11 +271,15 @@
 import com.google.android.collect.Lists;
 import com.google.common.collect.ImmutableList;
 
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
@@ -317,6 +322,9 @@
     private final int mUid = Binder.getCallingUid();
     private final @UserIdInt int mUserId = UserHandle.getUserId(mUid);
 
+    @Rule
+    public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
     private TestableNotificationManagerService mService;
     private INotificationManager mBinderService;
     private NotificationManagerInternal mInternalService;
@@ -679,7 +687,11 @@
                 mPackageIntentReceiver = broadcastReceivers.get(i);
             }
             if (filter.hasAction(Intent.ACTION_USER_SWITCHED)) {
-                mUserSwitchIntentReceiver = broadcastReceivers.get(i);
+                // There may be multiple receivers, get the NMS one
+                if (broadcastReceivers.get(i).toString().contains(
+                        NotificationManagerService.class.getName())) {
+                    mUserSwitchIntentReceiver = broadcastReceivers.get(i);
+                }
             }
         }
         assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
@@ -4828,6 +4840,62 @@
     }
 
     @Test
+    @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
+    public void testMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
+        Notification.MediaStyle style = new Notification.MediaStyle();
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setStyle(style);
+
+        NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
+
+        assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
+    }
+
+    @Test
+    @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
+    public void testCustomMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
+        Notification.DecoratedMediaCustomViewStyle style =
+                new Notification.DecoratedMediaCustomViewStyle();
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setStyle(style);
+
+        NotificationRecord posted = createAndPostNotification(nb,
+                "testCustomMediaStyleSetNoClearFlag");
+
+        assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
+    }
+
+    @Test
+    @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
+    public void testMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
+        Notification.MediaStyle style = new Notification.MediaStyle();
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setStyle(style);
+
+        NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
+
+        assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
+    }
+
+    @Test
+    @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
+    public void testCustomMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
+        Notification.DecoratedMediaCustomViewStyle style =
+                new Notification.DecoratedMediaCustomViewStyle();
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setStyle(style);
+
+        NotificationRecord posted = createAndPostNotification(nb,
+                "testCustomMediaStyleSetNoClearFlag");
+
+        assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
+    }
+
+    @Test
     public void testMediaStyleRemote_hasPermission() throws RemoteException {
         String deviceName = "device";
         mContext.getTestablePermissions().setPermission(
@@ -4838,17 +4906,8 @@
                 mTestNotificationChannel.getId())
                 .setStyle(style);
 
-        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
-                "testMediaStyleRemoteHasPermission", mUid, 0,
-                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
-        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
-        mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
-                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
-        waitForIdle();
-
-        NotificationRecord posted = mService.findNotificationLocked(
-                PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+        NotificationRecord posted = createAndPostNotification(nb,
+                "testMediaStyleRemoteHasPermission");
         Bundle extras = posted.getNotification().extras;
 
         assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
@@ -4866,17 +4925,8 @@
                 mTestNotificationChannel.getId())
                 .setStyle(style);
 
-        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
-                "testMediaStyleRemoteNoPermission", mUid, 0,
-                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
-        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
-        mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
-                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
-        waitForIdle();
-
-        NotificationRecord posted = mService.findNotificationLocked(
-                PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+        NotificationRecord posted = createAndPostNotification(nb,
+                "testMediaStyleRemoteNoPermission");
 
         assertFalse(posted.getNotification().extras
                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
@@ -4899,17 +4949,8 @@
                 mTestNotificationChannel.getId())
                 .setStyle(style);
 
-        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
-                "testCustomMediaStyleRemoteNoPermission", mUid, 0,
-                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
-        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
-        mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
-                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
-        waitForIdle();
-
-        NotificationRecord posted = mService.findNotificationLocked(
-                PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+        NotificationRecord posted = createAndPostNotification(nb,
+                "testCustomMediaStyleRemoteNoPermission");
 
         assertFalse(posted.getNotification().extras
                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
@@ -4929,16 +4970,9 @@
         Notification.Builder nb = new Notification.Builder(mContext,
                 mTestNotificationChannel.getId())
                 .addExtras(extras);
-        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
-                "testSubstituteAppNamePermission", mUid, 0,
-                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
-        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
-        mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
-                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
-        waitForIdle();
-        NotificationRecord posted = mService.findNotificationLocked(
-                PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+        NotificationRecord posted = createAndPostNotification(nb,
+                "testSubstituteAppNameHasPermission");
 
         assertTrue(posted.getNotification().extras
                 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
@@ -4955,16 +4989,9 @@
         Notification.Builder nb = new Notification.Builder(mContext,
                 mTestNotificationChannel.getId())
                 .addExtras(extras);
-        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
-                "testSubstituteAppNamePermission", mUid, 0,
-                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
-        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
-        mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
-                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
-        waitForIdle();
-        NotificationRecord posted = mService.findNotificationLocked(
-                PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+        NotificationRecord posted = createAndPostNotification(nb,
+                "testSubstituteAppNameNoPermission");
 
         assertFalse(posted.getNotification().extras
                 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
@@ -11358,7 +11385,7 @@
 
         long timePostedMs = System.currentTimeMillis();
         if (isExpired) {
-            timePostedMs -= BITMAP_EXPIRATION_TIME_MS;
+            timePostedMs -= BITMAP_DURATION.toMillis();
         }
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
                 notification, UserHandle.getUserHandleForUid(mUid), null, timePostedMs);
@@ -12656,6 +12683,20 @@
         verify(service, times(1)).setDNDMigrationDone(user.id);
     }
 
+    private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
+            throws RemoteException {
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, testName, mUid, 0,
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        return mService.findNotificationLocked(
+                PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+    }
+
     private static <T extends Parcelable> T parcelAndUnparcel(T source,
             Parcelable.Creator<T> creator) {
         Parcel parcel = Parcel.obtain();
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
index a91bd2b..0003555 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.vibrator;
 
+import static android.os.VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
+import static android.os.VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;
 import static android.os.VibrationEffect.EFFECT_TEXTURE_TICK;
@@ -24,8 +26,13 @@
 import static android.view.HapticFeedbackConstants.CONTEXT_CLICK;
 import static android.view.HapticFeedbackConstants.SAFE_MODE_ENABLED;
 import static android.view.HapticFeedbackConstants.TEXT_HANDLE_MOVE;
+import static android.view.HapticFeedbackConstants.SCROLL_ITEM_FOCUS;
+import static android.view.HapticFeedbackConstants.SCROLL_LIMIT;
+import static android.view.HapticFeedbackConstants.SCROLL_TICK;
+
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.Mockito.when;
 
@@ -37,6 +44,7 @@
 import android.os.VibratorInfo;
 import android.util.AtomicFile;
 import android.util.SparseArray;
+import android.view.flags.FeatureFlags;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -59,23 +67,25 @@
     private static final VibrationEffect PRIMITIVE_CLICK_EFFECT =
             VibrationEffect.startComposition().addPrimitive(PRIMITIVE_CLICK, 0.3497f).compose();
 
+    private static final int[] SCROLL_FEEDBACK_CONSTANTS =
+            new int[] {SCROLL_ITEM_FOCUS, SCROLL_LIMIT, SCROLL_TICK};
     private Context mContext = InstrumentationRegistry.getContext();
     private VibratorInfo mVibratorInfo = VibratorInfo.EMPTY_VIBRATOR_INFO;
 
     @Mock private Resources mResourcesMock;
+    @Mock private FeatureFlags mViewFeatureFlags;
 
     @Test
     public void testNonExistentCustomization_useDefault() throws Exception {
         // No customization file is set.
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
                 .isEqualTo(VibrationEffect.get(EFFECT_TICK));
 
         // The customization file specifies no customization.
         setupCustomizationFile("<haptic-feedback-constants></haptic-feedback-constants>");
-        hapticProvider = new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
+        hapticProvider = createProviderWithDefaultCustomizations();
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
                 .isEqualTo(VibrationEffect.get(EFFECT_TICK));
@@ -84,8 +94,7 @@
     @Test
     public void testExceptionParsingCustomizations_useDefault() throws Exception {
         setupCustomizationFile("<bad-xml></bad-xml>");
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
                 .isEqualTo(VibrationEffect.get(EFFECT_TICK));
@@ -97,8 +106,7 @@
         SparseArray<VibrationEffect> customizations = new SparseArray<>();
         customizations.put(CONTEXT_CLICK, PRIMITIVE_CLICK_EFFECT);
 
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
+        HapticFeedbackVibrationProvider hapticProvider = createProvider(customizations);
 
         // The override for `CONTEXT_CLICK` is used.
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
@@ -118,8 +126,7 @@
                 + "</haptic-feedback-constants>";
         setupCustomizationFile(xml);
 
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         // The override for `CONTEXT_CLICK` is not used because the vibration is not supported.
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
@@ -137,15 +144,12 @@
         customizations.put(TEXT_HANDLE_MOVE, PRIMITIVE_CLICK_EFFECT);
 
         // Test with a customization available for `TEXT_HANDLE_MOVE`.
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
+        HapticFeedbackVibrationProvider hapticProvider = createProvider(customizations);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE)).isNull();
 
         // Test with no customization available for `TEXT_HANDLE_MOVE`.
-        hapticProvider =
-                new HapticFeedbackVibrationProvider(
-                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null);
+        hapticProvider = createProvider(/* customizations= */ null);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE)).isNull();
     }
@@ -158,16 +162,13 @@
         customizations.put(TEXT_HANDLE_MOVE, PRIMITIVE_CLICK_EFFECT);
 
         // Test with a customization available for `TEXT_HANDLE_MOVE`.
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
+        HapticFeedbackVibrationProvider hapticProvider = createProvider(customizations);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE))
                 .isEqualTo(PRIMITIVE_CLICK_EFFECT);
 
         // Test with no customization available for `TEXT_HANDLE_MOVE`.
-        hapticProvider =
-                new HapticFeedbackVibrationProvider(
-                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null);
+        hapticProvider = createProvider(/* customizations= */ null);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE))
                 .isEqualTo(VibrationEffect.get(EFFECT_TEXTURE_TICK));
@@ -181,15 +182,13 @@
         SparseArray<VibrationEffect> customizations = new SparseArray<>();
         customizations.put(SAFE_MODE_ENABLED, PRIMITIVE_CLICK_EFFECT);
 
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
+        HapticFeedbackVibrationProvider hapticProvider = createProvider(customizations);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))
                 .isEqualTo(PRIMITIVE_CLICK_EFFECT);
 
         mockSafeModeEnabledVibration(null);
-        hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
+        hapticProvider = createProvider(customizations);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))
                 .isEqualTo(PRIMITIVE_CLICK_EFFECT);
@@ -199,9 +198,7 @@
     public void testNoValidCustomizationPresentForSafeModeEnabled_resourceBasedVibrationUsed()
                 throws Exception {
         mockSafeModeEnabledVibration(10, 20, 30, 40);
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(
-                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null);
+        HapticFeedbackVibrationProvider hapticProvider = createProvider(/* customizations= */ null);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))
                 .isEqualTo(VibrationEffect.createWaveform(new long[] {10, 20, 30, 40}, -1));
@@ -211,35 +208,65 @@
     public void testNoValidCustomizationAndResourcePresentForSafeModeEnabled_noVibrationUsed()
                 throws Exception {
         mockSafeModeEnabledVibration(null);
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(
-                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null);
+        HapticFeedbackVibrationProvider hapticProvider = createProvider(/* customizations= */ null);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED)).isNull();
     }
 
     @Test
     public void testVibrationAttribute_forNotBypassingIntensitySettings() {
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
                 SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ false);
 
-        assertThat(attrs.getFlags() & VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)
-                .isEqualTo(0);
+        assertThat(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)).isFalse();
     }
 
     @Test
     public void testVibrationAttribute_forByassingIntensitySettings() {
-        HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
                 SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ true);
 
-        assertThat(attrs.getFlags() & VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)
-                .isNotEqualTo(0);
+        assertThat(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)).isTrue();
+    }
+
+    @Test
+    public void testVibrationAttribute_scrollFeedback_scrollApiFlagOn_bypassInterruptPolicy() {
+        when(mViewFeatureFlags.scrollFeedbackApi()).thenReturn(true);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
+
+        for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
+            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
+                    effectId, /* bypassVibrationIntensitySetting= */ false);
+            assertWithMessage("Expected FLAG_BYPASS_INTERRUPTION_POLICY for effect " + effectId)
+                   .that(attrs.isFlagSet(FLAG_BYPASS_INTERRUPTION_POLICY)).isTrue();
+        }
+    }
+
+    @Test
+    public void testVibrationAttribute_scrollFeedback_scrollApiFlagOff_noBypassInterruptPolicy() {
+        when(mViewFeatureFlags.scrollFeedbackApi()).thenReturn(false);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
+
+        for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
+            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
+                    effectId, /* bypassVibrationIntensitySetting= */ false);
+            assertWithMessage("Expected no FLAG_BYPASS_INTERRUPTION_POLICY for effect " + effectId)
+                   .that(attrs.isFlagSet(FLAG_BYPASS_INTERRUPTION_POLICY)).isFalse();
+        }
+    }
+
+    private HapticFeedbackVibrationProvider createProviderWithDefaultCustomizations() {
+        return createProvider(/* customizations= */ null);
+    }
+
+    private HapticFeedbackVibrationProvider createProvider(
+            SparseArray<VibrationEffect> customizations) {
+        return new HapticFeedbackVibrationProvider(
+            mResourcesMock, mVibratorInfo, customizations, mViewFeatureFlags);
     }
 
     private void mockVibratorPrimitiveSupport(int... supportedPrimitives) {
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 0eec9cd..40e0e84 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -31,6 +31,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
@@ -46,6 +47,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.res.Resources;
 import android.hardware.input.IInputManager;
@@ -87,6 +89,7 @@
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
+import android.view.flags.FeatureFlags;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
@@ -172,6 +175,8 @@
     private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;
     @Mock
     private AudioManager mAudioManagerMock;
+    @Mock
+    private FeatureFlags mViewFeatureFlags;
 
     private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
 
@@ -321,7 +326,8 @@
                     HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(
                             Resources resources, VibratorInfo vibratorInfo) {
                         return new HapticFeedbackVibrationProvider(
-                                resources, vibratorInfo, mHapticFeedbackVibrationMap);
+                                resources, vibratorInfo, mHapticFeedbackVibrationMap,
+                                mViewFeatureFlags);
                     }
                 });
         return mService;
@@ -649,6 +655,42 @@
     }
 
     @Test
+    public void vibrate_withoutBypassFlagsPermissions_bypassFlagsNotApplied() throws Exception {
+        denyPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        denyPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
+        denyPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING);
+
+        assertCanVibrateWithBypassFlags(false);
+    }
+
+    @Test
+    public void vibrate_withSecureSettingsPermission_bypassFlagsApplied() throws Exception {
+        grantPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        denyPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
+        denyPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING);
+
+        assertCanVibrateWithBypassFlags(true);
+    }
+
+    @Test
+    public void vibrate_withModifyPhoneStatePermission_bypassFlagsApplied() throws Exception {
+        denyPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        grantPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
+        denyPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING);
+
+        assertCanVibrateWithBypassFlags(true);
+    }
+
+    @Test
+    public void vibrate_withModifyAudioRoutingPermission_bypassFlagsApplied() throws Exception {
+        denyPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        denyPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
+        grantPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING);
+
+        assertCanVibrateWithBypassFlags(true);
+    }
+
+    @Test
     public void vibrate_withRingtone_usesRingerModeSettings() throws Exception {
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
@@ -1166,7 +1208,7 @@
     }
 
     @Test
-    public void vibrate_withTriggerCallback_finishesVibration() throws Exception {
+    public void vibrate_withriggerCallback_finishesVibration() throws Exception {
         mockCapabilities(IVibratorManager.CAP_SYNC, IVibratorManager.CAP_PREPARE_COMPOSE);
         mockVibrators(1, 2);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
@@ -1303,10 +1345,18 @@
     }
 
     @Test
-    public void performHapticFeedback_doesNotRequirePermission() throws Exception {
+    public void performHapticFeedback_doesNotRequireVibrateOrBypassPermissions() throws Exception {
+        // Deny permissions that would have been required for regular vibrations, and check that
+        // the vibration proceed as expected to verify that haptic feedback does not need these
+        // permissions.
         denyPermission(android.Manifest.permission.VIBRATE);
+        denyPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        denyPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
+        denyPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING);
+        // Flag override to enable the scroll feedack constants to bypass interruption policies.
+        when(mViewFeatureFlags.scrollFeedbackApi()).thenReturn(true);
         mHapticFeedbackVibrationMap.put(
-                HapticFeedbackConstants.KEYBOARD_TAP,
+                HapticFeedbackConstants.SCROLL_TICK,
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
@@ -1315,13 +1365,16 @@
 
         HalVibration vibration =
                 performHapticFeedbackAndWaitUntilFinished(
-                        service, HapticFeedbackConstants.KEYBOARD_TAP, /* always= */ true);
+                        service, HapticFeedbackConstants.SCROLL_TICK, /* always= */ true);
 
         List<VibrationEffectSegment> playedSegments = fakeVibrator.getAllEffectSegments();
         assertEquals(1, playedSegments.size());
         PrebakedSegment segment = (PrebakedSegment) playedSegments.get(0);
         assertEquals(VibrationEffect.EFFECT_CLICK, segment.getEffectId());
-        assertEquals(VibrationAttributes.USAGE_TOUCH, vibration.callerInfo.attrs.getUsage());
+        VibrationAttributes attrs = vibration.callerInfo.attrs;
+        assertEquals(VibrationAttributes.USAGE_HARDWARE_FEEDBACK, attrs.getUsage());
+        assertTrue(attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF));
+        assertTrue(attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY));
     }
 
     @Test
@@ -2261,6 +2314,31 @@
         assertNull(metrics.halUnsupportedEffectsUsed);
     }
 
+    private void assertCanVibrateWithBypassFlags(boolean expectedCanApplyBypassFlags)
+            throws Exception {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        VibratorManagerService service = createSystemReadyService();
+
+        HalVibration vibration = vibrateAndWaitUntilFinished(
+                service,
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK),
+                new VibrationAttributes.Builder()
+                        .setUsage(VibrationAttributes.USAGE_TOUCH)
+                        .setFlags(
+                                VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF
+                                        | VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)
+                        .build());
+
+        VibrationAttributes attrs = vibration.callerInfo.attrs;
+        assertEquals(
+                expectedCanApplyBypassFlags,
+                attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF));
+        assertEquals(
+                expectedCanApplyBypassFlags,
+                attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY));
+    }
+
     private VibrationEffectSegment expectedPrebaked(int effectId) {
         return expectedPrebaked(effectId, VibrationEffect.EFFECT_STRENGTH_MEDIUM);
     }
@@ -2327,12 +2405,13 @@
         return vib;
     }
 
-    private void vibrateAndWaitUntilFinished(VibratorManagerService service, VibrationEffect effect,
-            VibrationAttributes attrs) throws InterruptedException {
-        vibrateAndWaitUntilFinished(service, CombinedVibration.createParallel(effect), attrs);
+    private HalVibration vibrateAndWaitUntilFinished(VibratorManagerService service,
+            VibrationEffect effect, VibrationAttributes attrs) throws InterruptedException {
+        return vibrateAndWaitUntilFinished(
+                service, CombinedVibration.createParallel(effect), attrs);
     }
 
-    private void vibrateAndWaitUntilFinished(VibratorManagerService service,
+    private HalVibration vibrateAndWaitUntilFinished(VibratorManagerService service,
             CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException {
         HalVibration vib =
                 service.vibrateWithPermissionCheck(UID, Display.DEFAULT_DISPLAY, PACKAGE_NAME,
@@ -2340,6 +2419,8 @@
         if (vib != null) {
             vib.waitForEnd();
         }
+
+        return vib;
     }
 
     private void vibrate(VibratorManagerService service, VibrationEffect effect,
@@ -2368,7 +2449,15 @@
         return predicateResult;
     }
 
+    private void grantPermission(String permission) {
+        when(mContextSpy.checkCallingOrSelfPermission(permission))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        doNothing().when(mContextSpy).enforceCallingOrSelfPermission(eq(permission), anyString());
+    }
+
     private void denyPermission(String permission) {
+        when(mContextSpy.checkCallingOrSelfPermission(permission))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
         doThrow(new SecurityException()).when(mContextSpy)
                 .enforceCallingOrSelfPermission(eq(permission), anyString());
     }
diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp
index e704ebf..744cb63 100644
--- a/services/tests/voiceinteractiontests/Android.bp
+++ b/services/tests/voiceinteractiontests/Android.bp
@@ -43,7 +43,7 @@
         "services.soundtrigger",
         "servicestests-core-utils",
         "servicestests-utils-mockito-extended",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index c2812a1..af39b2f 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -57,12 +57,14 @@
         "platform-test-annotations",
         "servicestests-utils",
         "testng",
-        "truth-prebuilt",
+        "truth",
         "testables",
         "hamcrest-library",
         "platform-compat-test-rules",
         "CtsSurfaceValidatorLib",
         "service-sdksandbox.impl",
+        "com.android.window.flags.window-aconfig-java",
+        "flag-junit",
     ],
 
     libs: [
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 42e3383..762e23c 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -47,6 +47,8 @@
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/>
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+    <uses-permission android:name="android.permission.MONITOR_INPUT"/>
 
     <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
     <application android:debuggable="true"
@@ -104,6 +106,11 @@
             android:showWhenLocked="true"
             android:turnScreenOn="true" />
 
+        <activity android:name="android.app.Activity"
+            android:exported="true"
+            android:showWhenLocked="true"
+            android:turnScreenOn="true" />
+
         <activity
             android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity"
             android:exported="true">
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
index 0a7bb00..71098aa 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
@@ -20,6 +20,7 @@
 import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ALL_APPS;
 import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ASSIST;
 import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_NOTIFICATION_PANEL;
+import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL;
 
 import android.platform.test.annotations.Presubmit;
 import android.view.KeyEvent;
@@ -284,6 +285,16 @@
                         KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_H, META_ON}};
     }
 
+    @Keep
+    private static Object[][] shortPressOnSettingsTestArguments() {
+        // testName, testKeys, shortPressOnSettingsBehavior, expectedLogEvent, expectedKey,
+        // expectedModifierState
+        return new Object[][]{
+                {"SETTINGS key -> Toggle Notification panel", new int[]{KeyEvent.KEYCODE_SETTINGS},
+                        SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL,
+                        KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_SETTINGS, 0}};
+    }
+
     @Before
     public void setUp() {
         setUpPhoneWindowManager(/*supportSettingsUpdate*/ true);
@@ -294,6 +305,7 @@
         mPhoneWindowManager.overrideEnableBugReportTrigger(true);
         mPhoneWindowManager.overrideStatusBarManagerInternal();
         mPhoneWindowManager.overrideStartActivity();
+        mPhoneWindowManager.overrideSendBroadcast();
         mPhoneWindowManager.overrideUserSetupComplete();
         mPhoneWindowManager.setupAssistForLaunch();
         mPhoneWindowManager.overrideTogglePanel();
@@ -330,4 +342,15 @@
         mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
                 expectedKey, expectedModifierState, "Failed while executing " + testName);
     }
+
+    @Test
+    @Parameters(method = "shortPressOnSettingsTestArguments")
+    public void testShortPressOnSettings(String testName, int[] testKeys,
+            int shortPressOnSettingsBehavior, KeyboardLogEvent expectedLogEvent, int expectedKey,
+            int expectedModifierState) {
+        mPhoneWindowManager.overrideShortPressOnSettingsBehavior(shortPressOnSettingsBehavior);
+        sendKeyCombination(testKeys, 0 /* duration */);
+        mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
+                expectedKey, expectedModifierState, "Failed while executing " + testName);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index ef28ffa..2244dbe 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -375,6 +375,10 @@
         mPhoneWindowManager.mDoubleTapOnHomeBehavior = behavior;
     }
 
+    void overrideShortPressOnSettingsBehavior(int behavior) {
+        mPhoneWindowManager.mShortPressOnSettingsBehavior = behavior;
+    }
+
     void overrideCanStartDreaming(boolean canDream) {
         doReturn(canDream).when(mDreamManagerInternal).canStartDreaming(anyBoolean());
     }
@@ -484,6 +488,10 @@
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
     }
 
+    void overrideSendBroadcast() {
+        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
+    }
+
     void overrideUserSetupComplete() {
         doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index cd0389d..ba31944 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -46,10 +46,13 @@
 import static com.google.common.truth.Truth.assertThat;
 
 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.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -583,6 +586,7 @@
         final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
         doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder();
         displayArea.mOrganizer = mockDisplayAreaOrganizer;
+        displayArea.mDisplayAreaAppearedSent = true;
         spyOn(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController);
         mDisplayContent.addChild(displayArea, 0);
 
@@ -687,6 +691,56 @@
         assertEquals(parent.getChildAt(0), child);
     }
 
+    @Test
+    public void testSetOrganizer() {
+        final TaskDisplayArea displayArea = createTaskDisplayArea(
+                mDisplayContent, mWm, "NewArea", FEATURE_VENDOR_FIRST);
+
+        assertNull(displayArea.mOrganizer);
+        assertFalse(displayArea.mDisplayAreaAppearedSent);
+
+        final IDisplayAreaOrganizer organizer = mock(IDisplayAreaOrganizer.class);
+        final DisplayAreaOrganizerController controller =
+                mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
+        spyOn(controller);
+        doNothing().when(controller).onDisplayAreaVanished(any(), any());
+
+        displayArea.setOrganizer(organizer);
+
+        assertEquals(organizer, displayArea.mOrganizer);
+        assertTrue(displayArea.mDisplayAreaAppearedSent);
+        verify(controller).onDisplayAreaAppeared(organizer, displayArea);
+
+        // No duplicated appeared sent.
+        clearInvocations(controller);
+        displayArea.sendDisplayAreaAppeared();
+
+        verify(controller, never()).onDisplayAreaAppeared(any(), any());
+
+        // Sent info changed after appeared.
+        displayArea.sendDisplayAreaInfoChanged();
+
+        verify(controller).onDisplayAreaInfoChanged(organizer, displayArea);
+
+        // Sent info vanished after appeared.
+        displayArea.setOrganizer(null);
+
+        verify(controller).onDisplayAreaVanished(organizer, displayArea);
+        assertNull(displayArea.mOrganizer);
+        assertFalse(displayArea.mDisplayAreaAppearedSent);
+
+        // No callback until appeared sent.
+        clearInvocations(controller);
+
+        displayArea.sendDisplayAreaAppeared();
+        displayArea.sendDisplayAreaInfoChanged();
+        displayArea.sendDisplayAreaVanished(organizer);
+
+        verify(controller, never()).onDisplayAreaAppeared(any(), any());
+        verify(controller, never()).onDisplayAreaInfoChanged(any(), any());
+        verify(controller, never()).onDisplayAreaVanished(any(), any());
+    }
+
     private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
         private TestDisplayArea(WindowManagerService wms, Rect bounds, String name) {
             super(wms, ANY, name);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 3bc6450..c241033 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -549,10 +549,12 @@
 
         // Let's pretend that the app has crashed.
         firstActivity.app.setThread(null);
-        mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
+        final Task finishedTask = mRootWindowContainer.finishTopCrashedActivities(
+                firstActivity.app, "test");
 
         // Verify that the root task was removed.
         assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount());
+        assertEquals(rootTask, finishedTask);
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java
index c1d5147..8119fd4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java
@@ -138,11 +138,11 @@
         IWindow window = IWindow.Stub.asInterface(mActivity.mSurfaceView.getWindowToken());
 
         WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(window,
-                mScvh1.getFocusGrantToken(), true);
+                mScvh1.getInputTransferToken(), true);
         assertTrue("Failed to gain focus for view1", waitForWindowFocus(mView1, true));
 
         WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(window,
-                mScvh2.getFocusGrantToken(), true);
+                mScvh2.getInputTransferToken(), true);
         assertTrue("Failed to gain focus for view2", waitForWindowFocus(mView2, true));
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 91256ee..4a33594 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -216,7 +216,7 @@
         try {
             final TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
             mWm.mTaskSnapshotController.createSnapshot(mAppWindow.mActivityRecord.getTask(),
-                    1f /* scaleFraction */, PixelFormat.UNKNOWN, null /* outTaskSize */, builder);
+                    1f /* scaleFraction */, new Rect() /* crop */, builder);
         } catch (NullPointerException e) {
             fail("There should be no exception when calling createTaskSnapshot");
         }
@@ -238,7 +238,7 @@
             spyOn(builder);
             mWm.mTaskSnapshotController.createSnapshot(
                     mAppWindow.mActivityRecord.getTask(), 1f /* scaleFraction */,
-                    PixelFormat.UNKNOWN, null /* outTaskSize */, builder);
+                    new Rect() /* crop */, builder);
             // Verify the builder should includes IME surface.
             verify(builder).setHasImeSurface(eq(true));
             builder.setColorSpace(ColorSpace.get(ColorSpace.Named.SRGB));
@@ -261,7 +261,7 @@
         final TaskSnapshot.Builder builder =
                 new TaskSnapshot.Builder();
         boolean success = mWm.mTaskSnapshotController.prepareTaskSnapshot(
-                mAppWindow.mActivityRecord.getTask(), PixelFormat.UNKNOWN, builder);
+                mAppWindow.mActivityRecord.getTask(), builder) != null;
 
         assertTrue(success);
         // The pixel format should be selected automatically.
@@ -270,7 +270,7 @@
         // Snapshot should not be taken while the rotation of activity and task are different.
         doReturn(true).when(mAppWindow.mActivityRecord).hasFixedRotationTransform();
         success = mWm.mTaskSnapshotController.prepareTaskSnapshot(
-                mAppWindow.mActivityRecord.getTask(), PixelFormat.UNKNOWN, builder);
+                mAppWindow.mActivityRecord.getTask(), builder) != null;
 
         assertFalse(success);
     }
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 75716b9..c8546c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -48,6 +48,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.window.flags.Flags.explicitRefreshRateHints;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -60,6 +61,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
@@ -84,6 +86,7 @@
 import android.window.ITaskOrganizer;
 import android.window.ITransitionPlayer;
 import android.window.RemoteTransition;
+import android.window.SystemPerformanceHinter;
 import android.window.TaskFragmentOrganizer;
 import android.window.TransitionInfo;
 
@@ -1081,6 +1084,7 @@
         makeWindowVisible(windows);
         mDisplayContent.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs);
         mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
+        mDisplayContent.mTransitionController.setSyncEngine(createTestBLASTSyncEngine());
         final TestTransitionPlayer player = registerTestTransitionPlayer();
 
         mDisplayContent.getDisplayRotation().setRotation(mDisplayContent.getRotation() + 1);
@@ -1441,7 +1445,7 @@
         // normally.
         mWm.mSyncEngine.abort(openTransition.getSyncId());
 
-        verify(taskSnapshotController, times(1)).recordSnapshot(eq(task2), eq(false));
+        verify(taskSnapshotController, times(1)).recordSnapshot(eq(task2));
 
         controller.finishTransition(openTransition);
 
@@ -1481,7 +1485,7 @@
 
         // Make sure we haven't called recordSnapshot (since we are transient, it shouldn't be
         // called until finish).
-        verify(taskSnapshotController, times(0)).recordSnapshot(eq(task1), eq(false));
+        verify(taskSnapshotController, times(0)).recordSnapshot(eq(task1));
 
         enteringAnimReports.clear();
         doCallRealMethod().when(mWm.mRoot).ensureActivitiesVisible(any(),
@@ -1514,7 +1518,7 @@
         assertFalse(activity1.isVisible());
         assertFalse(activity1.app.hasActivityInVisibleTask());
 
-        verify(taskSnapshotController, times(1)).recordSnapshot(eq(task1), eq(false));
+        verify(taskSnapshotController, times(1)).recordSnapshot(eq(task1));
         assertTrue(enteringAnimReports.contains(activity2));
     }
 
@@ -2432,6 +2436,45 @@
         assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
     }
 
+    @Test
+    public void testTransitionsTriggerPerformanceHints() {
+        assumeTrue(explicitRefreshRateHints());
+        SystemPerformanceHinter systemPerformanceHinter = mock(SystemPerformanceHinter.class);
+        final TransitionController controller = new TestTransitionController(mAtm);
+        final TestTransitionPlayer player = registerTestTransitionPlayer();
+
+        mSyncEngine = createTestBLASTSyncEngine();
+        controller.setSyncEngine(mSyncEngine);
+        controller.setSystemPerformanceHinter(systemPerformanceHinter);
+        SystemPerformanceHinter.HighPerfSession session = mock(
+                SystemPerformanceHinter.HighPerfSession.class);
+        doReturn(session).when(systemPerformanceHinter).startSession(anyInt(), anyInt(),
+                anyString());
+
+        final Transition transitA = createTestTransition(TRANSIT_OPEN, controller);
+        final Task task = createTask(mDisplayContent,
+                WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+        final ActivityRecord act = createActivityRecord(task);
+        act.setVisibleRequested(true);
+        act.setVisible(true);
+
+        controller.startCollectOrQueue(transitA, (deferred) -> {
+        });
+        transitA.collect(act);
+
+        verify(systemPerformanceHinter).startSession(
+                eq(SystemPerformanceHinter.HINT_SF), anyInt(), eq("Transition collected"));
+
+        transitA.start();
+        transitA.setAllReady();
+
+        // Aborting here doesn't abort the transition, it aborts the sync allowing the transition to
+        // finish successfully.
+        mSyncEngine.abort(transitA.getSyncId());
+        controller.finishTransition(transitA);
+        verify(session).close();
+    }
+
     private static void makeTaskOrganized(Task... tasks) {
         final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
         for (Task t : tasks) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
new file mode 100644
index 0000000..ac49839
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2023 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.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.server.wm.BuildUtils;
+import android.server.wm.CtsWindowInfoUtils;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.window.flags.Flags;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@Presubmit
+public class TrustedOverlayTests {
+    private static final String TAG = "TrustedOverlayTests";
+    private static final long TIMEOUT_S = 5L * BuildUtils.HW_TIMEOUT_MULTIPLIER;
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    @Rule
+    public TestName mName = new TestName();
+
+    @Rule
+    public final ActivityScenarioRule<Activity> mActivityRule = new ActivityScenarioRule<>(
+            Activity.class);
+
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivityRule.getScenario().onActivity(activity -> {
+            mActivity = activity;
+        });
+    }
+
+    @RequiresFlagsDisabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY)
+    @Test
+    public void setTrustedOverlayInputWindow() throws InterruptedException {
+        testTrustedOverlayChildHelper(false);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY)
+    public void setTrustedOverlayChildLayer() throws InterruptedException {
+        testTrustedOverlayChildHelper(true);
+    }
+
+    /**
+     * b/300659960 where setting spy window and trusted overlay were not happening in the same
+     * transaction causing the system to crash. This ensures there are no synchronization issues
+     * setting both spy window and trusted overlay.
+     */
+    @Test
+    public void setSpyWindowDoesntCrash() throws InterruptedException {
+        IBinder[] tokens = new IBinder[1];
+        CountDownLatch hostTokenReady = new CountDownLatch(1);
+        mInstrumentation.runOnMainSync(() -> {
+            WindowManager.LayoutParams params = mActivity.getWindow().getAttributes();
+            params.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+            params.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
+            mActivity.getWindow().setAttributes(params);
+
+            View rootView = mActivity.getWindow().getDecorView();
+            if (rootView.isAttachedToWindow()) {
+                tokens[0] = rootView.getWindowToken();
+                hostTokenReady.countDown();
+            } else {
+                rootView.getViewTreeObserver().addOnWindowAttachListener(
+                        new ViewTreeObserver.OnWindowAttachListener() {
+                            @Override
+                            public void onWindowAttached() {
+                                tokens[0] = rootView.getWindowToken();
+                                hostTokenReady.countDown();
+                            }
+
+                            @Override
+                            public void onWindowDetached() {
+                            }
+                        });
+            }
+        });
+
+        assertTrue("Failed to wait for host to get added",
+                hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS));
+
+        boolean[] foundTrusted = new boolean[1];
+        CtsWindowInfoUtils.waitForWindowInfos(
+                windowInfos -> {
+                    for (var windowInfo : windowInfos) {
+                        if (windowInfo.windowToken == tokens[0] && windowInfo.isTrustedOverlay) {
+                            foundTrusted[0] = true;
+                            return true;
+                        }
+                    }
+                    return false;
+                }, TIMEOUT_S, TimeUnit.SECONDS);
+
+        if (!foundTrusted[0]) {
+            CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName());
+        }
+
+        assertTrue("Failed to find window or was not marked trusted", foundTrusted[0]);
+    }
+
+    private void testTrustedOverlayChildHelper(boolean expectedTrustedChild)
+            throws InterruptedException {
+        IBinder[] tokens = new IBinder[2];
+        CountDownLatch hostTokenReady = new CountDownLatch(1);
+        mInstrumentation.runOnMainSync(() -> {
+            mActivity.getWindow().addPrivateFlags(PRIVATE_FLAG_TRUSTED_OVERLAY);
+            View rootView = mActivity.getWindow().getDecorView();
+            if (rootView.isAttachedToWindow()) {
+                tokens[0] = rootView.getWindowToken();
+                hostTokenReady.countDown();
+            } else {
+                rootView.getViewTreeObserver().addOnWindowAttachListener(
+                        new ViewTreeObserver.OnWindowAttachListener() {
+                            @Override
+                            public void onWindowAttached() {
+                                tokens[0] = rootView.getWindowToken();
+                                hostTokenReady.countDown();
+                            }
+
+                            @Override
+                            public void onWindowDetached() {
+                            }
+                        });
+            }
+        });
+
+        assertTrue("Failed to wait for host to get added",
+                hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS));
+
+        mInstrumentation.runOnMainSync(() -> {
+            WindowManager wm = mActivity.getSystemService(WindowManager.class);
+
+            View childView = new View(mActivity) {
+                @Override
+                protected void onAttachedToWindow() {
+                    super.onAttachedToWindow();
+                    tokens[1] = getWindowToken();
+                }
+            };
+            WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+            params.token = tokens[0];
+            params.type = TYPE_APPLICATION_PANEL;
+            wm.addView(childView, params);
+        });
+
+        boolean[] foundTrusted = new boolean[2];
+
+        CtsWindowInfoUtils.waitForWindowInfos(
+                windowInfos -> {
+                    for (var windowInfo : windowInfos) {
+                        if (windowInfo.windowToken == tokens[0]
+                                && windowInfo.isTrustedOverlay) {
+                            foundTrusted[0] = true;
+                        } else if (windowInfo.windowToken == tokens[1]
+                                && windowInfo.isTrustedOverlay) {
+                            foundTrusted[1] = true;
+                        }
+                    }
+                    return foundTrusted[0] && foundTrusted[1];
+                }, TIMEOUT_S, TimeUnit.SECONDS);
+
+        if (!foundTrusted[0] || !foundTrusted[1]) {
+            CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName());
+        }
+
+        assertTrue("Failed to find parent window or was not marked trusted", foundTrusted[0]);
+        assertEquals("Failed to find child window or was not marked trusted", expectedTrustedChild,
+                foundTrusted[1]);
+    }
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 58b5ae5..f3bf026 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -106,6 +106,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
@@ -201,7 +202,8 @@
     static final int MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED = 9;
 
     private final Object mLock = new Object();
-    Handler mHandler;
+    private Handler mHandler;
+    private Handler mIoHandler;
     AppOpsManager mAppOps;
     UserManager mUserManager;
     PackageManager mPackageManager;
@@ -233,7 +235,7 @@
     private final SparseArray<LinkedList<Event>> mReportedEvents = new SparseArray<>();
     final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
     final SparseArray<ActivityData> mVisibleActivities = new SparseArray();
-    @GuardedBy("mLock")
+    @GuardedBy("mLaunchTimeAlarmQueues") // Don't hold the main lock
     private final SparseArray<LaunchTimeAlarmQueue> mLaunchTimeAlarmQueues = new SparseArray<>();
     @GuardedBy("mUsageEventListeners") // Don't hold the main lock when calling out
     private final ArraySet<UsageStatsManagerInternal.UsageEventListener> mUsageEventListeners =
@@ -279,6 +281,38 @@
         }
     }
 
+    private final Handler.Callback mIoHandlerCallback = (msg) -> {
+        switch (msg.what) {
+            case MSG_UID_STATE_CHANGED: {
+                final int uid = msg.arg1;
+                final int procState = msg.arg2;
+
+                final int newCounter = (procState <= ActivityManager.PROCESS_STATE_TOP) ? 0 : 1;
+                synchronized (mUidToKernelCounter) {
+                    final int oldCounter = mUidToKernelCounter.get(uid, 0);
+                    if (newCounter != oldCounter) {
+                        mUidToKernelCounter.put(uid, newCounter);
+                        try {
+                            FileUtils.stringToFile(KERNEL_COUNTER_FILE, uid + " " + newCounter);
+                        } catch (IOException e) {
+                            Slog.w(TAG, "Failed to update counter set: " + e);
+                        }
+                    }
+                }
+                return true;
+            }
+            case MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK: {
+                final int userId = msg.arg1;
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
+                        "usageStatsHandleEstimatedLaunchTimesOnUser(" + userId + ")");
+                handleEstimatedLaunchTimesOnUserUnlock(userId);
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                return true;
+            }
+        }
+        return false;
+    };
+
     private final Injector mInjector;
 
     public UsageStatsService(Context context) {
@@ -299,6 +333,7 @@
         mPackageManager = getContext().getPackageManager();
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mHandler = new H(BackgroundThread.get().getLooper());
+        mIoHandler = new Handler(IoThread.get().getLooper(), mIoHandlerCallback);
 
         mAppStandby = mInjector.getAppStandbyController(getContext());
         mResponseStatsTracker = new BroadcastResponseStatsTracker(mAppStandby, getContext());
@@ -424,6 +459,9 @@
             }
             mUserUnlockedStates.remove(userId);
             mUserState.put(userId, null); // release the service (mainly for GC)
+        }
+
+        synchronized (mLaunchTimeAlarmQueues) {
             LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
             if (alarmQueue != null) {
                 alarmQueue.removeAllAlarms();
@@ -456,9 +494,12 @@
             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "loadPendingEvents");
             loadPendingEventsLocked(userId, pendingEvents);
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-            final LinkedList<Event> eventsInMem = mReportedEvents.get(userId);
-            if (eventsInMem != null) {
-                pendingEvents.addAll(eventsInMem);
+            synchronized (mReportedEvents) {
+                final LinkedList<Event> eventsInMem = mReportedEvents.get(userId);
+                if (eventsInMem != null) {
+                    pendingEvents.addAll(eventsInMem);
+                    mReportedEvents.remove(userId);
+                }
             }
             boolean needToFlush = !pendingEvents.isEmpty();
 
@@ -476,11 +517,12 @@
             }
             reportEvent(unlockEvent, userId);
 
-            mHandler.obtainMessage(MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK, userId, 0).sendToTarget();
+            mIoHandler.obtainMessage(MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK,
+                    userId, 0).sendToTarget();
 
-            // Remove all the stats stored in memory and in system DE.
-            mReportedEvents.remove(userId);
+            // Remove all the stats stored in system DE.
             deleteRecursively(new File(Environment.getDataSystemDeDirectory(userId), "usagestats"));
+
             // Force a flush to disk for the current user to ensure important events are persisted.
             // Note: there is a very very small chance that the system crashes between deleting
             // the stats above from DE and persisting them to CE here in which case we will lose
@@ -599,7 +641,7 @@
     private final IUidObserver mUidObserver = new UidObserver() {
         @Override
         public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
-            mHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget();
+            mIoHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget();
         }
 
         @Override
@@ -671,16 +713,18 @@
                 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED);
     }
 
-    private static void deleteRecursively(File f) {
-        File[] files = f.listFiles();
-        if (files != null) {
-            for (File subFile : files) {
-                deleteRecursively(subFile);
+    private static void deleteRecursively(final File path) {
+        if (path.isDirectory()) {
+            final File[] files = path.listFiles();
+            if (files != null) {
+                for (File subFile : files) {
+                    deleteRecursively(subFile);
+                }
             }
         }
 
-        if (f.exists() && !f.delete()) {
-            Slog.e(TAG, "Failed to delete " + f);
+        if (path.exists() && !path.delete()) {
+            Slog.e(TAG, "Failed to delete " + path);
         }
     }
 
@@ -873,6 +917,7 @@
         }
     }
 
+    @GuardedBy({"mLock", "mReportedEvents"})
     private void persistPendingEventsLocked(int userId) {
         final LinkedList<Event> pendingEvents = mReportedEvents.get(userId);
         if (pendingEvents == null || pendingEvents.isEmpty()) {
@@ -976,7 +1021,7 @@
                     + UserUsageStatsService.eventToString(event.mEventType);
             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, traceTag);
         }
-        synchronized (mLock) {
+        synchronized (mReportedEvents) {
             LinkedList<Event> events = mReportedEvents.get(userId);
             if (events == null) {
                 events = new LinkedList<>();
@@ -1241,6 +1286,9 @@
             Slog.i(TAG, "Removing user " + userId + " and all data.");
             mUserState.remove(userId);
             mAppTimeLimit.onUserRemoved(userId);
+        }
+
+        synchronized (mLaunchTimeAlarmQueues) {
             final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
             if (alarmQueue != null) {
                 alarmQueue.removeAllAlarms();
@@ -1271,6 +1319,13 @@
             }
         }
 
+        synchronized (mLaunchTimeAlarmQueues) {
+            final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
+            if (alarmQueue != null) {
+                alarmQueue.removeAlarmForKey(packageName);
+            }
+        }
+
         final int tokenRemoved;
         synchronized (mLock) {
             final long timeRemoved = System.currentTimeMillis();
@@ -1279,10 +1334,7 @@
                 // when the user service is initialized and package manager is queried.
                 return;
             }
-            final LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
-            if (alarmQueue != null) {
-                alarmQueue.removeAlarmForKey(packageName);
-            }
+
             final UserUsageStatsService userService = mUserState.get(userId);
             if (userService == null) {
                 return;
@@ -1492,60 +1544,63 @@
             estimatedLaunchTime = calculateEstimatedPackageLaunchTime(userId, packageName);
             mAppStandby.setEstimatedLaunchTime(packageName, userId, estimatedLaunchTime);
 
-            synchronized (mLock) {
-                LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
-                if (alarmQueue == null) {
-                    alarmQueue = new LaunchTimeAlarmQueue(
-                            userId, getContext(), BackgroundThread.get().getLooper());
-                    mLaunchTimeAlarmQueues.put(userId, alarmQueue);
-                }
-                alarmQueue.addAlarm(packageName,
-                        SystemClock.elapsedRealtime() + (estimatedLaunchTime - now));
-            }
+            getOrCreateLaunchTimeAlarmQueue(userId).addAlarm(packageName,
+                    SystemClock.elapsedRealtime() + (estimatedLaunchTime - now));
         }
         return estimatedLaunchTime;
     }
 
+    private LaunchTimeAlarmQueue getOrCreateLaunchTimeAlarmQueue(int userId) {
+        synchronized (mLaunchTimeAlarmQueues) {
+            LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
+            if (alarmQueue == null) {
+                alarmQueue = new LaunchTimeAlarmQueue(
+                    userId, getContext(), BackgroundThread.get().getLooper());
+                mLaunchTimeAlarmQueues.put(userId, alarmQueue);
+            }
+
+            return alarmQueue;
+        }
+    }
+
     @CurrentTimeMillisLong
     private long calculateEstimatedPackageLaunchTime(int userId, String packageName) {
-        synchronized (mLock) {
-            final long endTime = System.currentTimeMillis();
-            final long beginTime = endTime - ONE_WEEK;
-            final long unknownTime = endTime + UNKNOWN_LAUNCH_TIME_DELAY_MS;
-            final UsageEvents events = queryEarliestEventsForPackage(
-                    userId, beginTime, endTime, packageName, Event.ACTIVITY_RESUMED);
-            if (events == null) {
-                if (DEBUG) {
-                    Slog.d(TAG, "No events for " + userId + ":" + packageName);
-                }
-                return unknownTime;
+        final long endTime = System.currentTimeMillis();
+        final long beginTime = endTime - ONE_WEEK;
+        final long unknownTime = endTime + UNKNOWN_LAUNCH_TIME_DELAY_MS;
+        final UsageEvents events = queryEarliestEventsForPackage(
+                userId, beginTime, endTime, packageName, Event.ACTIVITY_RESUMED);
+        if (events == null) {
+            if (DEBUG) {
+                Slog.d(TAG, "No events for " + userId + ":" + packageName);
             }
-            final UsageEvents.Event event = new UsageEvents.Event();
-            final boolean hasMoreThan24HoursOfHistory;
-            if (events.getNextEvent(event)) {
-                hasMoreThan24HoursOfHistory = endTime - event.getTimeStamp() > ONE_DAY;
-                if (DEBUG) {
-                    Slog.d(TAG, userId + ":" + packageName + " history > 24 hours="
-                            + hasMoreThan24HoursOfHistory);
-                }
-            } else {
-                if (DEBUG) {
-                    Slog.d(TAG, userId + ":" + packageName + " has no events");
-                }
-                return unknownTime;
-            }
-            do {
-                if (event.getEventType() == Event.ACTIVITY_RESUMED) {
-                    final long timestamp = event.getTimeStamp();
-                    final long nextLaunch =
-                            calculateNextLaunchTime(hasMoreThan24HoursOfHistory, timestamp);
-                    if (nextLaunch > endTime) {
-                        return nextLaunch;
-                    }
-                }
-            } while (events.getNextEvent(event));
             return unknownTime;
         }
+        final UsageEvents.Event event = new UsageEvents.Event();
+        final boolean hasMoreThan24HoursOfHistory;
+        if (events.getNextEvent(event)) {
+            hasMoreThan24HoursOfHistory = endTime - event.getTimeStamp() > ONE_DAY;
+            if (DEBUG) {
+                Slog.d(TAG, userId + ":" + packageName + " history > 24 hours="
+                        + hasMoreThan24HoursOfHistory);
+            }
+        } else {
+            if (DEBUG) {
+                Slog.d(TAG, userId + ":" + packageName + " has no events");
+            }
+            return unknownTime;
+        }
+        do {
+            if (event.getEventType() == Event.ACTIVITY_RESUMED) {
+                final long timestamp = event.getTimeStamp();
+                final long nextLaunch =
+                        calculateNextLaunchTime(hasMoreThan24HoursOfHistory, timestamp);
+                if (nextLaunch > endTime) {
+                    return nextLaunch;
+                }
+            }
+        } while (events.getNextEvent(event));
+        return unknownTime;
     }
 
     @CurrentTimeMillisLong
@@ -1566,61 +1621,54 @@
     }
 
     private void handleEstimatedLaunchTimesOnUserUnlock(int userId) {
-        synchronized (mLock) {
-            final long nowElapsed = SystemClock.elapsedRealtime();
-            final long now = System.currentTimeMillis();
-            final long beginTime = now - ONE_WEEK;
-            final UsageEvents events = queryEarliestAppEvents(
-                    userId, beginTime, now, Event.ACTIVITY_RESUMED);
-            if (events == null) {
-                return;
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        final long now = System.currentTimeMillis();
+        final long beginTime = now - ONE_WEEK;
+        final UsageEvents events = queryEarliestAppEvents(
+                userId, beginTime, now, Event.ACTIVITY_RESUMED);
+        if (events == null) {
+            return;
+        }
+        final ArrayMap<String, Boolean> hasMoreThan24HoursOfHistory = new ArrayMap<>();
+        final UsageEvents.Event event = new UsageEvents.Event();
+        boolean changedTimes = false;
+        final LaunchTimeAlarmQueue alarmQueue = getOrCreateLaunchTimeAlarmQueue(userId);
+        for (boolean unprocessedEvent = events.getNextEvent(event); unprocessedEvent;
+                unprocessedEvent = events.getNextEvent(event)) {
+            final String packageName = event.getPackageName();
+            if (!hasMoreThan24HoursOfHistory.containsKey(packageName)) {
+                boolean hasHistory = now - event.getTimeStamp() > ONE_DAY;
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            userId + ":" + packageName + " history > 24 hours=" + hasHistory);
+                }
+                hasMoreThan24HoursOfHistory.put(packageName, hasHistory);
             }
-            final ArrayMap<String, Boolean> hasMoreThan24HoursOfHistory = new ArrayMap<>();
-            final UsageEvents.Event event = new UsageEvents.Event();
-            LaunchTimeAlarmQueue alarmQueue = mLaunchTimeAlarmQueues.get(userId);
-            if (alarmQueue == null) {
-                alarmQueue = new LaunchTimeAlarmQueue(
-                        userId, getContext(), BackgroundThread.get().getLooper());
-                mLaunchTimeAlarmQueues.put(userId, alarmQueue);
-            }
-            boolean changedTimes = false;
-            for (boolean unprocessedEvent = events.getNextEvent(event); unprocessedEvent;
-                    unprocessedEvent = events.getNextEvent(event)) {
-                final String packageName = event.getPackageName();
-                if (!hasMoreThan24HoursOfHistory.containsKey(packageName)) {
-                    boolean hasHistory = now - event.getTimeStamp() > ONE_DAY;
+            if (event.getEventType() == Event.ACTIVITY_RESUMED) {
+                long estimatedLaunchTime =
+                        mAppStandby.getEstimatedLaunchTime(packageName, userId);
+                if (estimatedLaunchTime < now || estimatedLaunchTime == Long.MAX_VALUE) {
+                    //noinspection ConstantConditions
+                    estimatedLaunchTime = calculateNextLaunchTime(
+                            hasMoreThan24HoursOfHistory.get(packageName), event.getTimeStamp());
+                    mAppStandby.setEstimatedLaunchTime(
+                            packageName, userId, estimatedLaunchTime);
+                }
+                if (estimatedLaunchTime < now + ONE_WEEK) {
+                    // Before a user is unlocked, we don't know when the app will be launched,
+                    // so we give callers the UNKNOWN time. Now that we have a better estimate,
+                    // we should notify them of the change.
                     if (DEBUG) {
-                        Slog.d(TAG,
-                                userId + ":" + packageName + " history > 24 hours=" + hasHistory);
+                        Slog.d(TAG, "User " + userId + " unlock resulting in"
+                                + " estimated launch time change for " + packageName);
                     }
-                    hasMoreThan24HoursOfHistory.put(packageName, hasHistory);
+                    changedTimes |= stageChangedEstimatedLaunchTime(userId, packageName);
                 }
-                if (event.getEventType() == Event.ACTIVITY_RESUMED) {
-                    long estimatedLaunchTime =
-                            mAppStandby.getEstimatedLaunchTime(packageName, userId);
-                    if (estimatedLaunchTime < now || estimatedLaunchTime == Long.MAX_VALUE) {
-                        //noinspection ConstantConditions
-                        estimatedLaunchTime = calculateNextLaunchTime(
-                                hasMoreThan24HoursOfHistory.get(packageName), event.getTimeStamp());
-                        mAppStandby.setEstimatedLaunchTime(
-                                packageName, userId, estimatedLaunchTime);
-                    }
-                    if (estimatedLaunchTime < now + ONE_WEEK) {
-                        // Before a user is unlocked, we don't know when the app will be launched,
-                        // so we give callers the UNKNOWN time. Now that we have a better estimate,
-                        // we should notify them of the change.
-                        if (DEBUG) {
-                            Slog.d(TAG, "User " + userId + " unlock resulting in"
-                                    + " estimated launch time change for " + packageName);
-                        }
-                        changedTimes |= stageChangedEstimatedLaunchTime(userId, packageName);
-                    }
-                    alarmQueue.addAlarm(packageName, nowElapsed + (estimatedLaunchTime - now));
-                }
+                alarmQueue.addAlarm(packageName, nowElapsed + (estimatedLaunchTime - now));
             }
-            if (changedTimes) {
-                mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
-            }
+        }
+        if (changedTimes) {
+            mHandler.sendEmptyMessage(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
         }
     }
 
@@ -1897,16 +1945,19 @@
                         idpw.println();
                     }
                 } else {
-                    final LinkedList<Event> pendingEvents = mReportedEvents.get(userId);
-                    if (pendingEvents != null && !pendingEvents.isEmpty()) {
-                        final int eventCount = pendingEvents.size();
-                        idpw.println("Pending events: count=" + eventCount);
-                        idpw.increaseIndent();
-                        for (int idx = 0; idx < eventCount; idx++) {
-                            UserUsageStatsService.printEvent(idpw, pendingEvents.get(idx), true);
+                    synchronized (mReportedEvents) {
+                        final LinkedList<Event> pendingEvents = mReportedEvents.get(userId);
+                        if (pendingEvents != null && !pendingEvents.isEmpty()) {
+                            final int eventCount = pendingEvents.size();
+                            idpw.println("Pending events: count=" + eventCount);
+                            idpw.increaseIndent();
+                            for (int idx = 0; idx < eventCount; idx++) {
+                                UserUsageStatsService.printEvent(idpw, pendingEvents.get(idx),
+                                        true);
+                            }
+                            idpw.decreaseIndent();
+                            idpw.println();
                         }
-                        idpw.decreaseIndent();
-                        idpw.println();
                     }
                 }
                 idpw.decreaseIndent();
@@ -1989,37 +2040,11 @@
                 case MSG_PACKAGE_REMOVED:
                     onPackageRemoved(msg.arg1, (String) msg.obj);
                     break;
-                case MSG_UID_STATE_CHANGED: {
-                    final int uid = msg.arg1;
-                    final int procState = msg.arg2;
-
-                    final int newCounter = (procState <= ActivityManager.PROCESS_STATE_TOP) ? 0 : 1;
-                    synchronized (mUidToKernelCounter) {
-                        final int oldCounter = mUidToKernelCounter.get(uid, 0);
-                        if (newCounter != oldCounter) {
-                            mUidToKernelCounter.put(uid, newCounter);
-                            try {
-                                FileUtils.stringToFile(KERNEL_COUNTER_FILE, uid + " " + newCounter);
-                            } catch (IOException e) {
-                                Slog.w(TAG, "Failed to update counter set: " + e);
-                            }
-                        }
-                    }
-                    break;
-                }
                 case MSG_ON_START:
                     synchronized (mLock) {
                         loadGlobalComponentUsageLocked();
                     }
                     break;
-                case MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK: {
-                    final int userId = msg.arg1;
-                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
-                            "usageStatsHandleEstimatedLaunchTimesOnUser(" + userId + ")");
-                    handleEstimatedLaunchTimesOnUserUnlock(userId);
-                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                }
-                break;
                 case MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED: {
                     removeMessages(MSG_NOTIFY_ESTIMATED_LAUNCH_TIMES_CHANGED);
 
@@ -2587,11 +2612,12 @@
         @Override
         public void reportChooserSelection(@NonNull String packageName, int userId,
                 @NonNull String contentType, String[] annotations, @NonNull String action) {
-            // A valid package name, content type, and action must be provided for these events
-            Objects.requireNonNull(packageName);
-            Objects.requireNonNull(contentType);
-            Objects.requireNonNull(action);
-            if (contentType.isBlank() || action.isBlank()) {
+            if (packageName == null) {
+                throw new IllegalArgumentException("Package selection must not be null.");
+            }
+            // A valid contentType and action must be provided for chooser selection events.
+            if (contentType == null || contentType.isBlank()
+                    || action == null || action.isBlank()) {
                 return;
             }
 
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 7d9b379..def52a5 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -942,6 +942,7 @@
          * @return the Telecom identifier associated with this {@link Call} . This is not a stable
          * identifier and is not guaranteed to be unique across device reboots.
          */
+        @FlaggedApi(Flags.FLAG_CALL_DETAILS_ID_CHANGES)
         public @NonNull String getId() { return mTelecomCallId; }
 
         /** {@hide} */
@@ -1894,7 +1895,7 @@
      * Tones are both played locally for the user to hear and sent to the network to be relayed
      * to the remote device.
      * <p>
-     * You must ensure that any call to {@link #playDtmfTone(char}) is followed by a matching
+     * You must ensure that any call to {@link #playDtmfTone(char)} is followed by a matching
      * call to {@link #stopDtmfTone()} and that each tone is stopped before a new one is started.
      * The play and stop commands are relayed to the underlying
      * {@link android.telecom.ConnectionService} as executed; implementations may not correctly
diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java
index 50f2ad4..24d3918 100644
--- a/telecomm/java/android/telecom/CallControl.java
+++ b/telecomm/java/android/telecom/CallControl.java
@@ -225,7 +225,7 @@
 
     /**
      * Request start a call streaming session. On receiving valid request, telecom will bind to
-     * the {@link CallStreamingService} implemented by a general call streaming sender. So that the
+     * the {@code CallStreamingService} implemented by a general call streaming sender. So that the
      * call streaming sender can perform streaming local device audio to another remote device and
      * control the call during streaming.
      *
diff --git a/telecomm/java/android/telecom/CallControlCallback.java b/telecomm/java/android/telecom/CallControlCallback.java
index eac2e64..0166022 100644
--- a/telecomm/java/android/telecom/CallControlCallback.java
+++ b/telecomm/java/android/telecom/CallControlCallback.java
@@ -69,7 +69,7 @@
     /**
      * Telecom is informing the client to answer an incoming call and set it to active.
      *
-     * @param videoState   see {@link android.telecom.CallAttributes.CallType} for valid states
+     * @param videoState   the video state
      * @param wasCompleted The {@link Consumer} to be completed. If the client can answer the call
      *                     on their end, {@link Consumer#accept(Object)} should be called with
      *                     {@link Boolean#TRUE}.
diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestion.java b/telecomm/java/android/telecom/PhoneAccountSuggestion.java
index d9f89d5..c83804f 100644
--- a/telecomm/java/android/telecom/PhoneAccountSuggestion.java
+++ b/telecomm/java/android/telecom/PhoneAccountSuggestion.java
@@ -68,7 +68,7 @@
 
     /**
      * Creates a new instance of {@link PhoneAccountSuggestion}. This constructor is intended for
-     * use by apps implementing a {@link PhoneAccountSuggestionService}, and generally should not be
+     * use by apps implementing a {@code PhoneAccountSuggestionService}, and generally should not be
      * used by dialer apps other than for testing purposes.
      *
      * @param handle The {@link PhoneAccountHandle} for this suggestion.
diff --git a/telecomm/java/android/telecom/StreamingCall.java b/telecomm/java/android/telecom/StreamingCall.java
index 29f436d..ad1b6f9 100644
--- a/telecomm/java/android/telecom/StreamingCall.java
+++ b/telecomm/java/android/telecom/StreamingCall.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
@@ -25,6 +26,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.server.telecom.flags.Flags;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -57,6 +60,7 @@
     /**
      * The ID associated with this call.  This is the same value as {@link CallControl#getCallId()}.
      */
+    @FlaggedApi(Flags.FLAG_CALL_DETAILS_ID_CHANGES)
     public static final String EXTRA_CALL_ID = "android.telecom.extra.CALL_ID";
 
     /**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a5e0638..63e91ad 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -519,8 +519,6 @@
     /**
      * Used in the Preferred Network Types menu to determine if the 2G option is displayed.
      * Value defaults to false as of Android T to discourage the use of insecure 2G protocols.
-     *
-     * @see #KEY_HIDE_ENABLE_2G
      */
     public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
 
@@ -5075,7 +5073,6 @@
          * MMTEL and RCS.
          * <p>
          * The default value for this configuration is {@code false}.
-         * @see android.telephony.ims.SipDelegateManager
          */
         public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL =
                 KEY_PREFIX + "ims_single_registration_required_bool";
@@ -5650,8 +5647,8 @@
          *     <li>{@link #KEY_CAPABILITY_TYPE_SMS_INT_ARRAY}</li>
          *     <li>{@link #KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY}</li>
          * </ul>
-         * <p> The values are defined in
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech}
+         * <p> The values are defined as {@code REGISTRATION_TECH_*} constants in
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase}.
          *
          * changing mmtel_requires_provisioning_bundle requires changes to
          * carrier_volte_provisioning_required_bool and vice versa
@@ -5663,12 +5660,12 @@
         /**
          * List of different RAT technologies on which Provisioning for Voice calling (IR.92)
          * is supported.
-         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE
          * <p>Possible values are,
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR}
+         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE
          */
         public static final String KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY =
                 KEY_PREFIX + "capability_type_voice_int_array";
@@ -5676,12 +5673,12 @@
         /**
          * List of different RAT technologies on which Provisioning for Video Telephony (IR.94)
          * is supported.
-         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO
          * <p>Possible values are,
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR}
+         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO
          */
         public static final String KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY =
                 KEY_PREFIX + "capability_type_video_int_array";
@@ -5689,24 +5686,24 @@
         /**
          * List of different RAT technologies on which Provisioning for XCAP over Ut for
          * supplementary services. (IR.92) is supported.
-         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT
          * <p>Possible values are,
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR}
+         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT
          */
         public static final String KEY_CAPABILITY_TYPE_UT_INT_ARRAY =
                 KEY_PREFIX + "capability_type_ut_int_array";
 
         /**
          * List of different RAT technologies on which Provisioning for SMS (IR.92) is supported.
-         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS
          * <p>Possible values are,
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR}
+         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS
          */
         public static final String KEY_CAPABILITY_TYPE_SMS_INT_ARRAY =
                 KEY_PREFIX + "capability_type_sms_int_array";
@@ -5714,12 +5711,12 @@
         /**
          * List of different RAT technologies on which Provisioning for Call Composer
          * (section 2.4 of RCC.20) is supported.
-         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER
          * <p>Possible values are,
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR}
+         * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER
          */
         public static final String KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY =
                 KEY_PREFIX + "capability_type_call_composer_int_array";
@@ -5734,8 +5731,8 @@
          *     <li>{@link #KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY}</li>
          *     <li>{@link #KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY}</li>
          * </ul>
-         * <p> The values are defined in
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech}
+         * <p> The values are defined as {@code REGISTRATION_TECH_*} constants in
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase}.
          */
         public static final String KEY_RCS_REQUIRES_PROVISIONING_BUNDLE =
                 KEY_PREFIX + "rcs_requires_provisioning_bundle";
@@ -5744,12 +5741,11 @@
          * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the
          * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS.
          * If not set, this RcsFeature should not service capability requests.
-         * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE
          * <p>Possible values are,
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY =
                 KEY_PREFIX + "capability_type_options_uce_int_array";
@@ -5759,12 +5755,11 @@
          * framework. If set, the RcsFeature should support capability exchange using a presence
          * server. If not set, this RcsFeature should not publish capabilities or service capability
          * requests using presence.
-         * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE
          * <p>Possible values are,
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_LTE}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM}
+         * {@link android.telephony.ims.stub.ImsRegistrationImplBase#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY =
                 KEY_PREFIX + "capability_type_presence_uce_int_array";
@@ -9541,9 +9536,9 @@
      * Used to trade privacy/security against potentially reduced carrier coverage for some
      * carriers.
      *
-     * @deprecated Future versions of Android will disallow carriers from hiding this toggle
-     * because disabling 2g is a security feature that users should always have access to at
-     * their discretion.
+     * @removed This config option is no longer supported as it was hiding a security feature
+     * from users. Setting this option will not change the behavior of the Settings menu starting
+     * in Android V.
      */
     @Deprecated
     public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool";
@@ -9642,7 +9637,7 @@
     /**
      * A list of premium capabilities the carrier supports. Applications can prompt users to
      * purchase these premium capabilities from their carrier for a performance boost.
-     * Valid values are any of {@link TelephonyManager.PremiumCapability}.
+     * Valid values are any of {@link TelephonyManager}'s {@code PREMIUM_CAPABILITY_*} constants.
      *
      * This is empty by default, indicating that no premium capabilities are supported.
      *
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index f9844bc..a8c077d 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -16,9 +16,12 @@
 
 package android.telephony;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 
+import com.android.internal.telephony.flags.Flags;
+
 /**
  * Describes the cause of a disconnected call. Those disconnect causes can be converted into a more
  * generic {@link android.telecom.DisconnectCause} object.
@@ -363,6 +366,7 @@
     /**
      * Indicates that the call was unable to be made because the satellite modem is enabled.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_ENABLED = 82;
 
     //*********************************************************************************************
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 631013f..7ccc27e 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,6 +31,8 @@
 import android.telephony.Annotation.NetworkType;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -206,6 +209,7 @@
     /**
      * MMS service
      */
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
     public static final int SERVICE_TYPE_MMS = 6;
 
     /** @hide  */
@@ -625,7 +629,7 @@
     }
 
     /**
-     * @return The access network technology {@link NetworkType}.
+     * @return The access network technology network type..
      */
     public @NetworkType int getAccessNetworkTechnology() {
         return mAccessNetworkTechnology;
@@ -702,6 +706,7 @@
      *
      * @return {@code true} if network is a non-terrestrial network else {@code false}.
      */
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
     public boolean isNonTerrestrialNetwork() {
         return mIsNonTerrestrialNetwork;
     }
@@ -1186,6 +1191,7 @@
          *                                            else {@code false}.
          * @return The builder.
          */
+        @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
         public @NonNull Builder setIsNonTerrestrialNetwork(boolean isNonTerrestrialNetwork) {
             mIsNonTerrestrialNetwork = isNonTerrestrialNetwork;
             return this;
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 5b8848c..85a85c6 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -35,6 +36,7 @@
 import android.telephony.NetworkRegistrationInfo.NRState;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.flags.Flags;
 import com.android.telephony.Rlog;
 
 import java.lang.annotation.Retention;
@@ -2256,6 +2258,7 @@
      *
      * @return {@code true} if device is connected to a non-terrestrial network else {@code false}.
      */
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
     public boolean isUsingNonTerrestrialNetwork() {
         synchronized (mNetworkRegistrationInfos) {
             for (NetworkRegistrationInfo nri : mNetworkRegistrationInfos) {
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index de2e952..6ebf3be 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -259,7 +259,7 @@
     /**
      * Whether this subscription is used for communicating with non-terrestrial networks.
      */
-    private final boolean mIsNtn;
+    private final boolean mIsOnlyNonTerrestrialNetwork;
 
     /**
      * @hide
@@ -385,7 +385,7 @@
         this.mAreUiccApplicationsEnabled = areUiccApplicationsEnabled;
         this.mPortIndex = portIndex;
         this.mUsageSetting = usageSetting;
-        this.mIsNtn = false;
+        this.mIsOnlyNonTerrestrialNetwork = false;
     }
 
     /**
@@ -424,7 +424,7 @@
         this.mAreUiccApplicationsEnabled = builder.mAreUiccApplicationsEnabled;
         this.mPortIndex = builder.mPortIndex;
         this.mUsageSetting = builder.mUsageSetting;
-        this.mIsNtn = builder.mIsNtn;
+        this.mIsOnlyNonTerrestrialNetwork = builder.mIsOnlyNonTerrestrialNetwork;
     }
 
     /**
@@ -878,8 +878,8 @@
      * otherwise.
      */
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public boolean isNtn() {
-        return mIsNtn;
+    public boolean isOnlyNonTerrestrialNetwork() {
+        return mIsOnlyNonTerrestrialNetwork;
     }
 
     @NonNull
@@ -918,7 +918,7 @@
                             UiccAccessRule.CREATOR))
                     .setUiccApplicationsEnabled(source.readBoolean())
                     .setUsageSetting(source.readInt())
-                    .setNtn(source.readBoolean())
+                    .setOnlyNonTerrestrialNetwork(source.readBoolean())
                     .build();
         }
 
@@ -960,7 +960,7 @@
         dest.writeTypedArray(mCarrierConfigAccessRules, flags);
         dest.writeBoolean(mAreUiccApplicationsEnabled);
         dest.writeInt(mUsageSetting);
-        dest.writeBoolean(mIsNtn);
+        dest.writeBoolean(mIsOnlyNonTerrestrialNetwork);
     }
 
     @Override
@@ -1023,7 +1023,7 @@
                 + " mType=" + SubscriptionManager.subscriptionTypeToString(mType)
                 + " areUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled
                 + " usageSetting=" + SubscriptionManager.usageSettingToString(mUsageSetting)
-                + " ntn=" + mIsNtn
+                + " isOnlyNonTerrestrialNetwork=" + mIsOnlyNonTerrestrialNetwork
                 + "]";
     }
 
@@ -1049,7 +1049,7 @@
                 that.mNativeAccessRules) && Arrays.equals(mCarrierConfigAccessRules,
                 that.mCarrierConfigAccessRules) && Objects.equals(mGroupUuid, that.mGroupUuid)
                 && mCountryIso.equals(that.mCountryIso) && mGroupOwner.equals(that.mGroupOwner)
-                && mIsNtn == that.mIsNtn;
+                && mIsOnlyNonTerrestrialNetwork == that.mIsOnlyNonTerrestrialNetwork;
     }
 
     @Override
@@ -1058,7 +1058,7 @@
                 mDisplayNameSource, mIconTint, mNumber, mDataRoaming, mMcc, mMnc, mIsEmbedded,
                 mCardString, mIsOpportunistic, mGroupUuid, mCountryIso, mCarrierId, mProfileClass,
                 mType, mGroupOwner, mAreUiccApplicationsEnabled, mPortIndex, mUsageSetting, mCardId,
-                mIsGroupDisabled, mIsNtn);
+                mIsGroupDisabled, mIsOnlyNonTerrestrialNetwork);
         result = 31 * result + Arrays.hashCode(mEhplmns);
         result = 31 * result + Arrays.hashCode(mHplmns);
         result = 31 * result + Arrays.hashCode(mNativeAccessRules);
@@ -1260,7 +1260,7 @@
         /**
          * {@code true} if it is a non-terrestrial network subscription, {@code false} otherwise.
          */
-        private boolean mIsNtn = false;
+        private boolean mIsOnlyNonTerrestrialNetwork = false;
 
         /**
          * Default constructor.
@@ -1304,7 +1304,7 @@
             mAreUiccApplicationsEnabled = info.mAreUiccApplicationsEnabled;
             mPortIndex = info.mPortIndex;
             mUsageSetting = info.mUsageSetting;
-            mIsNtn = info.mIsNtn;
+            mIsOnlyNonTerrestrialNetwork = info.mIsOnlyNonTerrestrialNetwork;
         }
 
         /**
@@ -1692,12 +1692,13 @@
         /**
          * Set whether the subscription is exclusively used for non-terrestrial networks or not.
          *
-         * @param isNtn {@code true} if the subscription is for NTN, {@code false} otherwise.
+         * @param isOnlyNonTerrestrialNetwork {@code true} if the subscription is for NTN,
+         * {@code false} otherwise.
          * @return The builder.
          */
         @NonNull
-        public Builder setNtn(boolean isNtn) {
-            mIsNtn = isNtn;
+        public Builder setOnlyNonTerrestrialNetwork(boolean isOnlyNonTerrestrialNetwork) {
+            mIsOnlyNonTerrestrialNetwork = isOnlyNonTerrestrialNetwork;
             return this;
         }
 
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index fa5fd87..8e90fe7 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1364,7 +1364,7 @@
     public static class OnSubscriptionsChangedListener {
 
         /**
-         * After {@link Build.VERSION_CODES.Q}, it is no longer necessary to instantiate a
+         * After {@link Build.VERSION_CODES#Q}, it is no longer necessary to instantiate a
          * Handler inside of the OnSubscriptionsChangedListener in all cases, so it will only
          * be done for callers that do not supply an Executor.
          */
@@ -1388,13 +1388,14 @@
         /**
          * Create an OnSubscriptionsChangedListener.
          *
-         * For callers targeting {@link Build.VERSION_CODES.P} or earlier, this can only be called
+         * For callers targeting {@link Build.VERSION_CODES#P} or earlier, this can only be called
          * on a thread that already has a prepared Looper. Callers targeting Q or later should
          * subsequently use {@link SubscriptionManager#addOnSubscriptionsChangedListener(
          * Executor, OnSubscriptionsChangedListener)}.
          *
-         * On OS versions prior to {@link Build.VERSION_CODES.V} callers should assume that this
-         * call will fail if invoked on a thread that does not already have a prepared looper.
+         * On OS versions prior to {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} callers should
+         * assume that this call will fail if invoked on a thread that does not already have a
+         * prepared looper.
          */
         public OnSubscriptionsChangedListener() {
             mCreatorLooper = Looper.myLooper();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 234ca91..90fa69f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -25,6 +25,7 @@
 import android.Manifest;
 import android.annotation.BytesLong;
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.LongDef;
 import android.annotation.NonNull;
@@ -128,6 +129,7 @@
 import com.android.internal.telephony.OperatorInfo;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.flags.Flags;
 import com.android.telephony.Rlog;
 
 import java.io.IOException;
@@ -1195,6 +1197,7 @@
      * The dialer app receives this event via
      * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final String EVENT_DISPLAY_SOS_MESSAGE =
             "android.telephony.event.DISPLAY_SOS_MESSAGE";
 
@@ -13132,8 +13135,8 @@
      * </ul>
      *
      * @param executor The executor on which the result listener will be called.
-     * @param resultListener {@link Consumer} that will be called with the result fetched
-     *                       from the radio of type {@link CarrierRestrictionStatus}
+     * @param resultListener {@link Consumer} that will be called with the carrier restriction
+     *                       status result fetched from the radio
      * @throws SecurityException if the caller does not have the required permission/privileges or
      *                           if the caller is not pre-registered.
      */
@@ -13465,7 +13468,7 @@
     public static final int DATA_ENABLED_REASON_THERMAL = 3;
 
     /**
-     * To indicate data was enabled or disabled due to {@link MobileDataPolicy} overrides.
+     * To indicate data was enabled or disabled due to mobile data policy overrides.
      * Note that this is not a valid reason for {@link #setDataEnabledForReason(int, boolean)} and
      * is only used to indicate that data enabled was changed due to an override.
      */
@@ -14571,7 +14574,7 @@
      * @param needValidation whether validation is needed before switch happens.
      * @param executor The executor of where the callback will execute.
      * @param callback Callback will be triggered once it succeeds or failed.
-     *                 See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
+     *                 See the {@code SET_OPPORTUNISTIC_SUB_*} constants
      *                 for more details. Pass null if don't care about the result.
      */
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
@@ -15036,6 +15039,7 @@
      * @hide
      */
     @TestApi
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int HAL_SERVICE_SATELLITE = 8;
 
     /** @hide */
@@ -17516,7 +17520,7 @@
     public @interface PurchasePremiumCapabilityResult {}
 
     /**
-     * Returns the purchase result {@link PurchasePremiumCapabilityResult} as a String.
+     * Returns the purchase result as a String.
      *
      * @param result The purchase premium capability result.
      * @return The purchase result as a String.
@@ -17570,7 +17574,6 @@
      * @param capability The premium capability to purchase.
      * @param executor The callback executor for the response.
      * @param callback The result of the purchase request.
-     *                 One of {@link PurchasePremiumCapabilityResult}.
      * @throws SecurityException if the caller does not hold permissions
      *         READ_BASIC_PHONE_STATE or INTERNET.
      * @see #isPremiumCapabilityAvailableForPurchase(int) to check whether the capability is valid.
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 26c17a4..e9af486 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -532,7 +532,7 @@
     /**
      * Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
      * up by this APN setting. Note this value will only be used when MTU size is not provided
-     * in {@link DataCallResponse#getMtuV4()} during network bring up.
+     * in {@code DataCallResponse#getMtuV4()} during network bring up.
      *
      * @return the MTU size in bytes of the route.
      */
@@ -542,7 +542,7 @@
 
     /**
      * Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
-     * will only be used when MTU size is not provided in {@link DataCallResponse#getMtuV6()}
+     * will only be used when MTU size is not provided in {@code DataCallResponse#getMtuV6()}
      * during network bring up.
      *
      * @return the MTU size in bytes of the route.
@@ -1787,7 +1787,7 @@
         /**
          * Set the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
          * up by this APN setting. Note this value will only be used when MTU size is not provided
-         * in {@link DataCallResponse#getMtuV4()} during network bring up.
+         * in {@code DataCallResponse#getMtuV4()} during network bring up.
          *
          * @param mtuV4 the MTU size in bytes of the route.
          */
@@ -1799,7 +1799,7 @@
         /**
          * Set the default MTU (Maximum Transmission Unit) size in bytes of the IPv6 routes brought
          * up by this APN setting. Note this value will only be used when MTU size is not provided
-         * in {@link DataCallResponse#getMtuV6()} during network bring up.
+         * in {@code DataCallResponse#getMtuV6()} during network bring up.
          *
          * @param mtuV6 the MTU size in bytes of the route.
          */
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index ed46276..b9a7d43 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -249,7 +249,7 @@
      *
      * <p>{@link #EXTRA_USE_QR_SCANNER} not set or set to false: The LPA should try to get an
      * activation code from the carrier app by binding to the carrier app service implementing
-     * {@link android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE}.
+     * {@code android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE}.
      * <p>{@link #EXTRA_USE_QR_SCANNER} set to true: The LPA should launch a QR scanner for the user
      * to scan an eSIM profile QR code.
      *
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index caee4e2..2172d7d 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -561,7 +561,7 @@
      * @param c The MmTel {@link CapabilityCallback} to be registered.
      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
      * @throws ImsException if the subscription associated with this callback is valid, but
-     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the {@code ImsService} associated with the subscription is not available. This can happen if
      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
      * reason.
      */
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 4439e5c..2b49bcd 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -247,7 +247,7 @@
      * @param c The {@link RegistrationManager.RegistrationCallback} to be added.
      * @see #unregisterImsRegistrationCallback(RegistrationManager.RegistrationCallback)
      * @throws ImsException if the subscription associated with this callback is valid, but
-     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the {@code ImsService} associated with the subscription is not available. This can happen if
      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
      * reason.
      */
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 37a6a7e..1c5d1e9 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -1469,9 +1469,8 @@
     /**
      * Get the provisioning status for the IMS MmTel capability specified.
      *
-     * If provisioning is not required for the queried
-     * {@link MmTelFeature.MmTelCapabilities.MmTelCapability} and
-     * {@link ImsRegistrationImplBase.ImsRegistrationTech} combination specified, this method will
+     * If provisioning is not required for the queried {@code capability} and
+     * {@code tech} combination specified, this method will
      * always return {@code true}.
      *
      * <p> Requires Permission:
@@ -1503,7 +1502,7 @@
      * Get the provisioning status for the IMS RCS capability specified.
      *
      * If provisioning is not required for the queried
-     * {@link ImsRcsManager.RcsImsCapabilityFlag} or if the device does not support IMS
+     * {@code capability} or if the device does not support IMS
      * this method will always return {@code true}.
      *
      * @see CarrierConfigManager.Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL
@@ -1533,7 +1532,7 @@
      * Get the provisioning status for the IMS RCS capability specified.
      *
      * If provisioning is not required for the queried
-     * {@link ImsRcsManager.RcsImsCapabilityFlag} or if the device does not support IMS
+     * {@code capability} or if the device does not support IMS
      * this method will always return {@code true}.
      *
      * <p> Requires Permission:
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 873ce60..b528866 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -31,7 +31,6 @@
 import android.telephony.AccessNetworkConstants;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
-import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 
@@ -42,7 +41,7 @@
 import java.util.function.Consumer;
 
 /**
- * Manages IMS Service registration state for associated {@link ImsFeature}s.
+ * Manages IMS Service registration state for associated {@code ImsFeature}s.
  */
 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
 public interface RegistrationManager {
@@ -394,7 +393,7 @@
      * @param c The {@link RegistrationCallback} to be added.
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
      * @throws ImsException if the subscription associated with this callback is valid, but
-     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the {@code ImsService} associated with the subscription is not available. This can happen if
      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
      * reason.
      */
diff --git a/telephony/java/android/telephony/satellite/AntennaDirection.java b/telephony/java/android/telephony/satellite/AntennaDirection.java
index 22412e6..c690f98 100644
--- a/telephony/java/android/telephony/satellite/AntennaDirection.java
+++ b/telephony/java/android/telephony/satellite/AntennaDirection.java
@@ -16,11 +16,14 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.util.Objects;
 
 /**
@@ -38,6 +41,7 @@
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public final class AntennaDirection implements Parcelable {
     /** Antenna x axis direction. */
     private float mX;
@@ -62,11 +66,13 @@
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public int describeContents() {
         return 0;
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeFloat(mX);
         out.writeFloat(mY);
@@ -74,6 +80,7 @@
     }
 
     @NonNull
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final Creator<AntennaDirection> CREATOR =
             new Creator<>() {
                 @Override
@@ -118,14 +125,17 @@
         return Objects.hash(mX, mY, mZ);
     }
 
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public float getX() {
         return mX;
     }
 
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public float getY() {
         return mY;
     }
 
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public float getZ() {
         return mZ;
     }
diff --git a/telephony/java/android/telephony/satellite/AntennaPosition.java b/telephony/java/android/telephony/satellite/AntennaPosition.java
index 588be6c..8842886 100644
--- a/telephony/java/android/telephony/satellite/AntennaPosition.java
+++ b/telephony/java/android/telephony/satellite/AntennaPosition.java
@@ -16,11 +16,14 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.util.Objects;
 
 /**
@@ -29,6 +32,7 @@
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public final class AntennaPosition implements Parcelable {
     /** Antenna direction used for satellite communication. */
     @NonNull AntennaDirection mAntennaDirection;
@@ -49,17 +53,20 @@
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public int describeContents() {
         return 0;
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeParcelable(mAntennaDirection, flags);
         out.writeInt(mSuggestedHoldPosition);
     }
 
     @NonNull
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final Creator<AntennaPosition> CREATOR =
             new Creator<>() {
                 @Override
@@ -100,11 +107,13 @@
     }
 
     @NonNull
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public AntennaDirection getAntennaDirection() {
         return mAntennaDirection;
     }
 
     @SatelliteManager.DeviceHoldPosition
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public int getSuggestedHoldPosition() {
         return mSuggestedHoldPosition;
     }
diff --git a/telephony/java/android/telephony/satellite/PointingInfo.java b/telephony/java/android/telephony/satellite/PointingInfo.java
index dc4d38b..022a856 100644
--- a/telephony/java/android/telephony/satellite/PointingInfo.java
+++ b/telephony/java/android/telephony/satellite/PointingInfo.java
@@ -16,11 +16,14 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.util.Objects;
 
 /**
@@ -30,6 +33,7 @@
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public final class PointingInfo implements Parcelable {
     /** Satellite azimuth in degrees */
     private float mSatelliteAzimuthDegrees;
@@ -50,16 +54,19 @@
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public int describeContents() {
         return 0;
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeFloat(mSatelliteAzimuthDegrees);
         out.writeFloat(mSatelliteElevationDegrees);
     }
 
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final @android.annotation.NonNull Creator<PointingInfo> CREATOR =
             new Creator<PointingInfo>() {
                 @Override
@@ -101,10 +108,12 @@
         return sb.toString();
     }
 
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public float getSatelliteAzimuthDegrees() {
         return mSatelliteAzimuthDegrees;
     }
 
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public float getSatelliteElevationDegrees() {
         return mSatelliteElevationDegrees;
     }
diff --git a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
index bc45be1..0d8f101 100644
--- a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
+++ b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
@@ -16,12 +16,15 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -34,6 +37,7 @@
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public final class SatelliteCapabilities implements Parcelable {
     /**
      * List of technologies supported by the satellite modem.
@@ -76,11 +80,13 @@
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public int describeContents() {
         return 0;
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void writeToParcel(@NonNull Parcel out, int flags) {
         if (mSupportedRadioTechnologies != null && !mSupportedRadioTechnologies.isEmpty()) {
             out.writeInt(mSupportedRadioTechnologies.size());
@@ -106,6 +112,7 @@
         }
     }
 
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     @NonNull public static final Creator<SatelliteCapabilities> CREATOR = new Creator<>() {
         @Override
         public SatelliteCapabilities createFromParcel(Parcel in) {
@@ -165,6 +172,7 @@
     /**
      * @return The list of technologies supported by the satellite modem.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     @NonNull @SatelliteManager.NTRadioTechnology public Set<Integer>
             getSupportedRadioTechnologies() {
         return mSupportedRadioTechnologies;
@@ -176,6 +184,7 @@
      * @return {@code true} if UE needs to point to a satellite to send and receive data and
      *         {@code false} otherwise.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public boolean isPointingRequired() {
         return mIsPointingRequired;
     }
@@ -185,6 +194,7 @@
      *
      * @return The maximum number of bytes per datagram that can be sent over satellite.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public int getMaxBytesPerOutgoingDatagram() {
         return mMaxBytesPerOutgoingDatagram;
     }
@@ -195,6 +205,7 @@
      * @return Map key: {@link SatelliteManager.DeviceHoldPosition} value: AntennaPosition
      */
     @NonNull
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public Map<Integer, AntennaPosition> getAntennaPositionMap() {
         return mAntennaPositionMap;
     }
diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagram.java b/telephony/java/android/telephony/satellite/SatelliteDatagram.java
index 9037f0c..4d67f80 100644
--- a/telephony/java/android/telephony/satellite/SatelliteDatagram.java
+++ b/telephony/java/android/telephony/satellite/SatelliteDatagram.java
@@ -16,17 +16,21 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.telephony.flags.Flags;
+
 /**
  * SatelliteDatagram is used to store data that is to be sent or received over satellite.
  * Data is stored in byte array format.
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public final class SatelliteDatagram implements Parcelable {
     /**
      * Datagram to be sent or received over satellite.
@@ -45,15 +49,18 @@
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public int describeContents() {
         return 0;
     }
 
     @Override
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeByteArray(mData);
     }
 
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     @NonNull public static final Creator<SatelliteDatagram> CREATOR =
             new Creator<>() {
                 @Override
@@ -73,6 +80,7 @@
      * satellite provider. Client application should be aware of how to encode the datagram based
      * upon the satellite provider.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     @NonNull public byte[] getSatelliteDatagram() {
         return mData;
     }
diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
index cb2920f..b5763c3 100644
--- a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
@@ -16,9 +16,12 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.util.function.Consumer;
 
 /**
@@ -27,6 +30,7 @@
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public interface SatelliteDatagramCallback {
     /**
      * Called when there is an incoming datagram to be received.
@@ -38,6 +42,7 @@
      *                 that they received the datagram. If the callback is not received within
      *                 five minutes, Telephony will resend the datagram.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     void onSatelliteDatagramReceived(long datagramId, @NonNull SatelliteDatagram datagram,
             int pendingCount, @NonNull Consumer<Void> callback);
 }
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 8dc2de8..7322aeb 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -63,6 +63,7 @@
  */
 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SATELLITE)
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public final class SatelliteManager {
     private static final String TAG = "SatelliteManager";
 
@@ -108,6 +109,7 @@
     /**
      * Exception from the satellite service containing the {@link SatelliteResult} error code.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static class SatelliteException extends Exception {
         @SatelliteResult private final int mErrorCode;
 
@@ -116,6 +118,7 @@
          *
          * @param errorCode The {@link SatelliteResult}.
          */
+        @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
         public SatelliteException(@SatelliteResult int errorCode) {
             mErrorCode = errorCode;
         }
@@ -125,6 +128,7 @@
          *
          * @return The {@link SatelliteResult}.
          */
+        @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
         @SatelliteResult public int getErrorCode() {
             return mErrorCode;
         }
@@ -190,104 +194,127 @@
     /**
      * The request was successfully processed.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_SUCCESS = 0;
     /**
      * A generic error which should be used only when other specific errors cannot be used.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_ERROR = 1;
     /**
      * Error received from the satellite server.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_SERVER_ERROR = 2;
     /**
      * Error received from the vendor service. This generic error code should be used
      * only when the error cannot be mapped to other specific service error codes.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_SERVICE_ERROR = 3;
     /**
      * Error received from satellite modem. This generic error code should be used only when
      * the error cannot be mapped to other specific modem error codes.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_MODEM_ERROR = 4;
     /**
      * Error received from the satellite network. This generic error code should be used only when
      * the error cannot be mapped to other specific network error codes.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_NETWORK_ERROR = 5;
     /**
      * Telephony is not in a valid state to receive requests from clients.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6;
     /**
      * Satellite modem is not in a valid state to receive requests from clients.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7;
     /**
      * Either vendor service, or modem, or Telephony framework has received a request with
      * invalid arguments from its clients.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8;
     /**
      * Telephony framework failed to send a request or receive a response from the vendor service
      * or satellite modem due to internal error.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_REQUEST_FAILED = 9;
     /**
      * Radio did not start or is resetting.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10;
     /**
      * The request is not supported by either the satellite modem or the network.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11;
     /**
      * Satellite modem or network has no resources available to handle requests from clients.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_NO_RESOURCES = 12;
     /**
      * Satellite service is not provisioned yet.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13;
     /**
      * Satellite service provision is already in progress.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14;
     /**
      * The ongoing request was aborted by either the satellite modem or the network.
      * This error is also returned when framework decides to abort current send request as one
      * of the previous send request failed.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15;
     /**
      * The device/subscriber is barred from accessing the satellite service.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_ACCESS_BARRED = 16;
     /**
      * Satellite modem timeout to receive ACK or response from the satellite network after
      * sending a request to the network.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17;
     /**
      * Satellite network is not reachable from the modem.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_NOT_REACHABLE = 18;
     /**
      * The device/subscriber is not authorized to register with the satellite service provider.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19;
     /**
      * The device does not support satellite.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20;
 
     /**
      * The current request is already in-progress.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21;
 
     /**
      * Satellite modem is currently busy due to which current request cannot be processed.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_RESULT_MODEM_BUSY = 22;
 
     /** @hide */
@@ -323,22 +350,27 @@
      * Unknown Non-Terrestrial radio technology. This generic radio technology should be used
      * only when the radio technology cannot be mapped to other specific radio technologies.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0;
     /**
      * 3GPP NB-IoT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int NT_RADIO_TECHNOLOGY_NB_IOT_NTN = 1;
     /**
      * 3GPP 5G NR over Non-Terrestrial-Networks technology.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2;
     /**
      * 3GPP eMTC (enhanced Machine-Type Communication) over Non-Terrestrial-Networks technology.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int NT_RADIO_TECHNOLOGY_EMTC_NTN = 3;
     /**
      * Proprietary technology.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4;
 
     /** @hide */
@@ -353,12 +385,16 @@
     public @interface NTRadioTechnology {}
 
     /** Suggested device hold position is unknown. */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DEVICE_HOLD_POSITION_UNKNOWN = 0;
     /** User is suggested to hold the device in portrait mode. */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DEVICE_HOLD_POSITION_PORTRAIT = 1;
     /** User is suggested to hold the device in landscape mode with left hand. */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2;
     /** User is suggested to hold the device in landscape mode with right hand. */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT = 3;
 
     /** @hide */
@@ -372,14 +408,18 @@
     public @interface DeviceHoldPosition {}
 
     /** Display mode is unknown. */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DISPLAY_MODE_UNKNOWN = 0;
     /** Display mode of the device used for satellite communication for non-foldable phones. */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DISPLAY_MODE_FIXED = 1;
     /** Display mode of the device used for satellite communication for foldabale phones when the
      * device is opened. */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DISPLAY_MODE_OPENED = 2;
     /** Display mode of the device used for satellite communication for foldabable phones when the
      * device is closed. */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DISPLAY_MODE_CLOSED = 3;
 
     /** @hide */
@@ -414,7 +454,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -457,7 +497,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void requestIsSatelliteEnabled(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
@@ -512,7 +552,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void requestIsDemoModeEnabled(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
@@ -565,7 +605,7 @@
      *
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void requestIsSatelliteSupported(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
@@ -619,7 +659,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void requestSatelliteCapabilities(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) {
         Objects.requireNonNull(executor);
@@ -664,16 +704,19 @@
      * The default state indicating that datagram transfer is idle.
      * This should be sent if there are no message transfer activity happening.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0;
     /**
      * A transition state indicating that a datagram is being sent.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING = 1;
     /**
      * An end state indicating that datagram sending completed successfully.
      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
      * will be sent if no more messages are pending.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2;
     /**
      * An end state indicating that datagram sending completed with a failure.
@@ -681,16 +724,19 @@
      * must be sent before reporting any additional datagram transfer state changes. All pending
      * messages will be reported as failed, to the corresponding applications.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3;
     /**
      * A transition state indicating that a datagram is being received.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING = 4;
     /**
      * An end state indicating that datagram receiving completed successfully.
      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
      * will be sent if no more messages are pending.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS = 5;
     /**
      * An end state indicating that datagram receive operation found that there are no
@@ -698,12 +744,14 @@
      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
      * will be sent if no more messages are pending.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6;
     /**
      * An end state indicating that datagram receive completed with a failure.
      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
      * will be sent if no more messages are pending.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7;
     /**
      * A transition state indicating that Telephony is waiting for satellite modem to connect to a
@@ -721,6 +769,7 @@
      * only when the datagram transfer state cannot be mapped to other specific datagram transfer
      * states.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1;
 
     /** @hide */
@@ -743,26 +792,32 @@
     /**
      * Satellite modem is in idle state.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_MODEM_STATE_IDLE = 0;
     /**
      * Satellite modem is listening for incoming datagrams.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_MODEM_STATE_LISTENING = 1;
     /**
      * Satellite modem is sending and/or receiving datagrams.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2;
     /**
      * Satellite modem is retrying to send and/or receive datagrams.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3;
     /**
      * Satellite modem is powered off.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_MODEM_STATE_OFF = 4;
     /**
      * Satellite modem is unavailable.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5;
     /**
      * The satellite modem is powered on but the device is not registered to a satellite cell.
@@ -778,6 +833,7 @@
      * Satellite modem state is unknown. This generic modem state should be used only when the
      * modem state cannot be mapped to other specific modem states.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1;
 
     /** @hide */
@@ -799,15 +855,18 @@
      * Datagram type is unknown. This generic datagram type should be used only when the
      * datagram type cannot be mapped to other specific datagram types.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DATAGRAM_TYPE_UNKNOWN = 0;
     /**
      * Datagram type indicating that the datagram to be sent or received is of type SOS message.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1;
     /**
      * Datagram type indicating that the datagram to be sent or received is of type
      * location sharing.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2;
 
     /** @hide */
@@ -857,7 +916,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void startSatelliteTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener,
             @NonNull SatelliteTransmissionUpdateCallback callback) {
@@ -927,7 +986,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void stopSatelliteTransmissionUpdates(
             @NonNull SatelliteTransmissionUpdateCallback callback,
             @NonNull @CallbackExecutor Executor executor,
@@ -983,7 +1042,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
             @Nullable CancellationSignal cancellationSignal,
             @NonNull @CallbackExecutor Executor executor,
@@ -1036,7 +1095,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void deprovisionSatelliteService(@NonNull String token,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1076,7 +1135,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     @SatelliteResult public int registerForSatelliteProvisionStateChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteProvisionStateCallback callback) {
@@ -1119,7 +1178,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void unregisterForSatelliteProvisionStateChanged(
             @NonNull SatelliteProvisionStateCallback callback) {
         Objects.requireNonNull(callback);
@@ -1158,7 +1217,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void requestIsSatelliteProvisioned(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
@@ -1210,7 +1269,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     @SatelliteResult public int registerForSatelliteModemStateChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteStateCallback callback) {
@@ -1250,7 +1309,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void unregisterForSatelliteModemStateChanged(@NonNull SatelliteStateCallback callback) {
         Objects.requireNonNull(callback);
         ISatelliteStateCallback internalCallback = sSatelliteStateCallbackMap.remove(callback);
@@ -1288,7 +1347,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     @SatelliteResult public int registerForSatelliteDatagram(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteDatagramCallback callback) {
@@ -1344,7 +1403,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void unregisterForSatelliteDatagram(@NonNull SatelliteDatagramCallback callback) {
         Objects.requireNonNull(callback);
         ISatelliteDatagramCallback internalCallback =
@@ -1383,7 +1442,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void pollPendingSatelliteDatagrams(@NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
@@ -1436,7 +1495,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void sendSatelliteDatagram(@DatagramType int datagramType,
             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
             @NonNull @CallbackExecutor Executor executor,
@@ -1482,7 +1541,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
@@ -1540,7 +1599,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void requestTimeForNextSatelliteVisibility(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Duration, SatelliteException> callback) {
         Objects.requireNonNull(executor);
@@ -1594,7 +1653,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     public void setDeviceAlignedWithSatellite(boolean isAligned) {
         try {
             ITelephony telephony = getITelephony();
@@ -1628,7 +1687,7 @@
      * @param subId The subscription ID of the carrier.
      * @param enableSatellite {@code true} to enable the satellite and {@code false} to disable.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1662,7 +1721,7 @@
      *                 will return a {@code boolean} with value {@code true} if the satellite
      *                 is enabled and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1688,7 +1747,7 @@
      * @param subId The subscription ID of the carrier.
      * @param reason Reason for disallowing satellite communication.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1731,7 +1790,7 @@
      * @param subId The subscription ID of the carrier.
      * @param reason Reason for disallowing satellite communication.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
diff --git a/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java
index 7116876..a12952b 100644
--- a/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java
@@ -16,14 +16,18 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.SystemApi;
 
+import com.android.internal.telephony.flags.Flags;
+
 /**
  * A callback class for monitoring satellite provision state change events.
  *
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public interface SatelliteProvisionStateCallback {
     /**
      * Called when satellite provision state changes.
@@ -33,5 +37,6 @@
      *                    It is generally expected that the provisioning app retries if
      *                    provisioning fails.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     void onSatelliteProvisionStateChanged(boolean provisioned);
 }
diff --git a/telephony/java/android/telephony/satellite/SatelliteStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteStateCallback.java
index 812ff2d..bfe6e10 100644
--- a/telephony/java/android/telephony/satellite/SatelliteStateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteStateCallback.java
@@ -16,18 +16,23 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.SystemApi;
 
+import com.android.internal.telephony.flags.Flags;
+
 /**
  * A callback class for monitoring satellite modem state change events.
  *
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public interface SatelliteStateCallback {
     /**
      * Called when satellite modem state changes.
      * @param state The new satellite modem state.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state);
 }
diff --git a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
index 7ac06b0..e020970 100644
--- a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
@@ -16,9 +16,12 @@
 
 package android.telephony.satellite;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 
+import com.android.internal.telephony.flags.Flags;
+
 /**
  * A callback class for monitoring satellite position update and datagram transfer state change
  * events.
@@ -26,12 +29,14 @@
  * @hide
  */
 @SystemApi
+@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
 public interface SatelliteTransmissionUpdateCallback {
     /**
      * Called when the satellite position changed.
      *
      * @param pointingInfo The pointing info containing the satellite location.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     void onSatellitePositionChanged(@NonNull PointingInfo pointingInfo);
 
     /**
@@ -41,6 +46,7 @@
      * @param sendPendingCount The number of datagrams that are currently being sent.
      * @param errorCode If datagram transfer failed, the reason for failure.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     void onSendDatagramStateChanged(
             @SatelliteManager.SatelliteDatagramTransferState int state, int sendPendingCount,
             @SatelliteManager.SatelliteResult int errorCode);
@@ -52,6 +58,7 @@
      * @param receivePendingCount The number of datagrams that are currently pending to be received.
      * @param errorCode If datagram transfer failed, the reason for failure.
      */
+    @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
     void onReceiveDatagramStateChanged(
             @SatelliteManager.SatelliteDatagramTransferState int state, int receivePendingCount,
             @SatelliteManager.SatelliteResult int errorCode);
diff --git a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
index 0fcd0d6..7fda550 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
@@ -32,15 +32,15 @@
      *
      * @param listener The callback interface to handle satellite service indications.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void setSatelliteListener(in ISatelliteListener listener);
 
@@ -53,15 +53,15 @@
      *                disabling listening mode.
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void requestSatelliteListeningEnabled(in boolean enable, in int timeout,
             in IIntegerConsumer resultCallback);
@@ -84,15 +84,15 @@
      * @param enableDemoMode True to enable demo mode and false to disable.
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void requestSatelliteEnabled(in boolean enableSatellite, in boolean enableDemoMode,
             in IIntegerConsumer resultCallback);
@@ -101,39 +101,42 @@
      * Request to get whether the satellite modem is enabled.
      *
      * @param resultCallback The callback to receive the error code result of the operation.
-     *                       This must only be sent when the error is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 whether the satellite modem is enabled.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive whether the satellite modem is enabled.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    void requestIsSatelliteEnabled(in IIntegerConsumer resultCallback, in IBooleanConsumer callback);
+    void requestIsSatelliteEnabled(in IIntegerConsumer resultCallback,
+            in IBooleanConsumer callback);
 
     /**
      * Request to get whether the satellite service is supported on the device.
      *
      * @param resultCallback The callback to receive the error code result of the operation.
-     *                       This must only be sent when the error is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 whether the satellite service is supported on the device.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive whether the satellite service is supported on the device.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void requestIsSatelliteSupported(in IIntegerConsumer resultCallback,
             in IBooleanConsumer callback);
@@ -142,19 +145,20 @@
      * Request to get the SatelliteCapabilities of the satellite service.
      *
      * @param resultCallback The callback to receive the error code result of the operation.
-     *                       This must only be sent when the error is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 the SatelliteCapabilities of the satellite service.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive the SatelliteCapabilities of the satellite service.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void requestSatelliteCapabilities(in IIntegerConsumer resultCallback,
             in ISatelliteCapabilitiesConsumer callback);
@@ -166,15 +170,15 @@
      *
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void startSendingSatellitePointingInfo(in IIntegerConsumer resultCallback);
 
@@ -184,15 +188,15 @@
      *
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void stopSendingSatellitePointingInfo(in IIntegerConsumer resultCallback);
 
@@ -206,18 +210,18 @@
      * @param provisionData Data from the provisioning app that can be used by provisioning server
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:NETWORK_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:REQUEST_ABORTED
-     *   SatelliteError:NETWORK_TIMEOUT
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_ABORTED
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_TIMEOUT
      */
     void provisionSatelliteService(in String token, in byte[] provisionData,
             in IIntegerConsumer resultCallback);
@@ -230,18 +234,18 @@
      * @param token The token of the device/subscription to be deprovisioned.
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:NETWORK_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:REQUEST_ABORTED
-     *   SatelliteError:NETWORK_TIMEOUT
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_ABORTED
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_TIMEOUT
      */
     void deprovisionSatelliteService(in String token, in IIntegerConsumer resultCallback);
 
@@ -249,19 +253,20 @@
      * Request to get whether this device is provisioned with a satellite provider.
      *
      * @param resultCallback The callback to receive the error code result of the operation.
-     *                       This must only be sent when the error is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 whether this device is provisioned with a satellite provider.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive whether this device is provisioned with a satellite provider.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void requestIsSatelliteProvisioned(in IIntegerConsumer resultCallback,
             in IBooleanConsumer callback);
@@ -273,20 +278,20 @@
      *
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:NETWORK_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:SATELLITE_ACCESS_BARRED
-     *   SatelliteError:NETWORK_TIMEOUT
-     *   SatelliteError:SATELLITE_NOT_REACHABLE
-     *   SatelliteError:NOT_AUTHORIZED
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_ACCESS_BARRED
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_TIMEOUT
+     *   SatelliteResult:SATELLITE_RESULT_NOT_REACHABLE
+     *   SatelliteResult:SATELLITE_RESULT_NOT_AUTHORIZED
      */
     void pollPendingSatelliteDatagrams(in IIntegerConsumer resultCallback);
 
@@ -297,21 +302,21 @@
      * @param isEmergency Whether this is an emergency datagram.
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:NETWORK_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:REQUEST_ABORTED
-     *   SatelliteError:SATELLITE_ACCESS_BARRED
-     *   SatelliteError:NETWORK_TIMEOUT
-     *   SatelliteError:SATELLITE_NOT_REACHABLE
-     *   SatelliteError:NOT_AUTHORIZED
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_ABORTED
+     *   SatelliteResult:SATELLITE_RESULT_ACCESS_BARRED
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_TIMEOUT
+     *   SatelliteResult:SATELLITE_RESULT_NOT_REACHABLE
+     *   SatelliteResult:SATELLITE_RESULT_NOT_AUTHORIZED
      */
     void sendSatelliteDatagram(in SatelliteDatagram datagram, in boolean isEmergency,
             in IIntegerConsumer resultCallback);
@@ -322,19 +327,20 @@
      * ISatelliteListener#onSatelliteModemStateChanged.
      *
      * @param resultCallback The callback to receive the error code result of the operation.
-     *                       This must only be sent when the error is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 the current satellite modem state.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive the current satellite modem state.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void requestSatelliteModemState(in IIntegerConsumer resultCallback,
             in IIntegerConsumer callback);
@@ -343,19 +349,20 @@
      * Request to get whether satellite communication is allowed for the current location.
      *
      * @param resultCallback The callback to receive the error code result of the operation.
-     *                       This must only be sent when the error is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 whether satellite communication is allowed for the current location.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive whether satellite communication is allowed for the current location.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void requestIsSatelliteCommunicationAllowedForCurrentLocation(
             in IIntegerConsumer resultCallback, in IBooleanConsumer callback);
@@ -366,19 +373,20 @@
      * This will return 0 if the satellite is currently visible.
      *
      * @param resultCallback The callback to receive the error code result of the operation.
-     *                       This must only be sent when the error is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 the time after which the satellite will be visible.
+     *                       This must only be sent when the result is not
+          *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive the time after which the satellite will be visible.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     void requestTimeForNextSatelliteVisibility(in IIntegerConsumer resultCallback,
             in IIntegerConsumer callback);
@@ -399,14 +407,14 @@
      *                             attach to them.
      * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:NONE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:MODEM_ERR
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     * Valid result codes returned:
+     *   SatelliteResult:NONE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:MODEM_ERR
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
      */
     void setSatellitePlmn(int simSlot, in List<String> carrierPlmnList,
             in List<String> allSatellitePlmnList, in IIntegerConsumer resultCallback);
@@ -420,12 +428,12 @@
      * @param serial Serial number of request.
      * @param enable {@code true} to enable satellite, {@code false} to disable satellite.
      *
-     * Valid errors returned:
-     *   SatelliteError:NONE
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:MODEM_ERR
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
      */
     void setSatelliteEnabledForCarrier(int simSlot, boolean satelliteEnabled,
          in IIntegerConsumer callback);
@@ -437,12 +445,12 @@
      *                this information to determine the relevant carrier.
      * @param serial Serial number of request.
      *
-     * Valid errors returned:
-     *   SatelliteError:NONE
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:MODEM_ERR
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
      */
     void requestIsSatelliteEnabledForCarrier(int simSlot, in IIntegerConsumer resultCallback,
             in IBooleanConsumer callback);
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
index a9c09c9..4cee01e 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
@@ -72,172 +72,172 @@
 
         @Override
         public void requestSatelliteListeningEnabled(boolean enable, int timeout,
-                IIntegerConsumer errorCallback) throws RemoteException {
+                IIntegerConsumer resultCallback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .requestSatelliteListeningEnabled(enable, timeout, errorCallback),
+                            .requestSatelliteListeningEnabled(enable, timeout, resultCallback),
                     "requestSatelliteListeningEnabled");
         }
 
         @Override
         public void enableCellularModemWhileSatelliteModeIsOn(boolean enabled,
-                IIntegerConsumer errorCallback) throws RemoteException {
+                IIntegerConsumer resultCallback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .enableCellularModemWhileSatelliteModeIsOn(enabled, errorCallback),
+                            .enableCellularModemWhileSatelliteModeIsOn(enabled, resultCallback),
                     "enableCellularModemWhileSatelliteModeIsOn");
         }
 
         @Override
         public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
-                IIntegerConsumer errorCallback) throws RemoteException {
+                IIntegerConsumer resultCallback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
                             .requestSatelliteEnabled(
-                                    enableSatellite, enableDemoMode, errorCallback),
+                                    enableSatellite, enableDemoMode, resultCallback),
                     "requestSatelliteEnabled");
         }
 
         @Override
-        public void requestIsSatelliteEnabled(IIntegerConsumer errorCallback,
+        public void requestIsSatelliteEnabled(IIntegerConsumer resultCallback,
                 IBooleanConsumer callback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .requestIsSatelliteEnabled(errorCallback, callback),
+                            .requestIsSatelliteEnabled(resultCallback, callback),
                     "requestIsSatelliteEnabled");
         }
 
         @Override
-        public void requestIsSatelliteSupported(IIntegerConsumer errorCallback,
+        public void requestIsSatelliteSupported(IIntegerConsumer resultCallback,
                 IBooleanConsumer callback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .requestIsSatelliteSupported(errorCallback, callback),
+                            .requestIsSatelliteSupported(resultCallback, callback),
                     "requestIsSatelliteSupported");
         }
 
         @Override
-        public void requestSatelliteCapabilities(IIntegerConsumer errorCallback,
+        public void requestSatelliteCapabilities(IIntegerConsumer resultCallback,
                 ISatelliteCapabilitiesConsumer callback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .requestSatelliteCapabilities(errorCallback, callback),
+                            .requestSatelliteCapabilities(resultCallback, callback),
                     "requestSatelliteCapabilities");
         }
 
         @Override
-        public void startSendingSatellitePointingInfo(IIntegerConsumer errorCallback)
+        public void startSendingSatellitePointingInfo(IIntegerConsumer resultCallback)
                 throws RemoteException {
             executeMethodAsync(
-                    () -> SatelliteImplBase.this.startSendingSatellitePointingInfo(errorCallback),
+                    () -> SatelliteImplBase.this.startSendingSatellitePointingInfo(resultCallback),
                     "startSendingSatellitePointingInfo");
         }
 
         @Override
-        public void stopSendingSatellitePointingInfo(IIntegerConsumer errorCallback)
+        public void stopSendingSatellitePointingInfo(IIntegerConsumer resultCallback)
                 throws RemoteException {
             executeMethodAsync(
-                    () -> SatelliteImplBase.this.stopSendingSatellitePointingInfo(errorCallback),
+                    () -> SatelliteImplBase.this.stopSendingSatellitePointingInfo(resultCallback),
                     "stopSendingSatellitePointingInfo");
         }
 
         @Override
         public void provisionSatelliteService(String token, byte[] provisionData,
-                IIntegerConsumer errorCallback) throws RemoteException {
+                IIntegerConsumer resultCallback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .provisionSatelliteService(token, provisionData, errorCallback),
+                            .provisionSatelliteService(token, provisionData, resultCallback),
                     "provisionSatelliteService");
         }
 
         @Override
-        public void deprovisionSatelliteService(String token, IIntegerConsumer errorCallback)
+        public void deprovisionSatelliteService(String token, IIntegerConsumer resultCallback)
                 throws RemoteException {
             executeMethodAsync(
-                    () -> SatelliteImplBase.this.deprovisionSatelliteService(token, errorCallback),
+                    () -> SatelliteImplBase.this.deprovisionSatelliteService(token, resultCallback),
                     "deprovisionSatelliteService");
         }
 
         @Override
-        public void requestIsSatelliteProvisioned(IIntegerConsumer errorCallback,
+        public void requestIsSatelliteProvisioned(IIntegerConsumer resultCallback,
                 IBooleanConsumer callback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .requestIsSatelliteProvisioned(errorCallback, callback),
+                            .requestIsSatelliteProvisioned(resultCallback, callback),
                     "requestIsSatelliteProvisioned");
         }
 
         @Override
-        public void pollPendingSatelliteDatagrams(IIntegerConsumer errorCallback)
+        public void pollPendingSatelliteDatagrams(IIntegerConsumer resultCallback)
                 throws RemoteException {
             executeMethodAsync(
-                    () -> SatelliteImplBase.this.pollPendingSatelliteDatagrams(errorCallback),
+                    () -> SatelliteImplBase.this.pollPendingSatelliteDatagrams(resultCallback),
                     "pollPendingSatelliteDatagrams");
         }
 
         @Override
         public void sendSatelliteDatagram(SatelliteDatagram datagram, boolean isEmergency,
-                IIntegerConsumer errorCallback) throws RemoteException {
+                IIntegerConsumer resultCallback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .sendSatelliteDatagram(datagram, isEmergency, errorCallback),
+                            .sendSatelliteDatagram(datagram, isEmergency, resultCallback),
                     "sendSatelliteDatagram");
         }
 
         @Override
-        public void requestSatelliteModemState(IIntegerConsumer errorCallback,
+        public void requestSatelliteModemState(IIntegerConsumer resultCallback,
                 IIntegerConsumer callback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .requestSatelliteModemState(errorCallback, callback),
+                            .requestSatelliteModemState(resultCallback, callback),
                     "requestSatelliteModemState");
         }
 
         @Override
         public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
-                IIntegerConsumer errorCallback, IBooleanConsumer callback)
+                IIntegerConsumer resultCallback, IBooleanConsumer callback)
                 throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
                             .requestIsSatelliteCommunicationAllowedForCurrentLocation(
-                                    errorCallback, callback),
+                                    resultCallback, callback),
                     "requestIsSatelliteCommunicationAllowedForCurrentLocation");
         }
 
         @Override
-        public void requestTimeForNextSatelliteVisibility(IIntegerConsumer errorCallback,
+        public void requestTimeForNextSatelliteVisibility(IIntegerConsumer resultCallback,
                 IIntegerConsumer callback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .requestTimeForNextSatelliteVisibility(errorCallback, callback),
+                            .requestTimeForNextSatelliteVisibility(resultCallback, callback),
                     "requestTimeForNextSatelliteVisibility");
         }
 
         @Override
         public void setSatellitePlmn(int simSlot, List<String> carrierPlmnList,
-                List<String> devicePlmnList, IIntegerConsumer errorCallback)
+                List<String> devicePlmnList, IIntegerConsumer resultCallback)
                 throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this.setSatellitePlmn(
-                            simSlot, carrierPlmnList, devicePlmnList, errorCallback),
+                            simSlot, carrierPlmnList, devicePlmnList, resultCallback),
                     "setSatellitePlmn");
         }
 
         @Override
         public void setSatelliteEnabledForCarrier(int simSlot, boolean enableSatellite,
-                IIntegerConsumer errorCallback) throws RemoteException {
+                IIntegerConsumer resultCallback) throws RemoteException {
             executeMethodAsync(
-                    () -> SatelliteImplBase.this
-                            .setSatelliteEnabledForCarrier(simSlot, enableSatellite, errorCallback),
+                    () -> SatelliteImplBase.this.setSatelliteEnabledForCarrier(
+                            simSlot, enableSatellite, resultCallback),
                     "setSatelliteEnabledForCarrier");
         }
 
         @Override
-        public void requestIsSatelliteEnabledForCarrier(int simSlot, IIntegerConsumer errorCallback,
-                IBooleanConsumer callback) throws RemoteException {
+        public void requestIsSatelliteEnabledForCarrier(int simSlot,
+                IIntegerConsumer resultCallback, IBooleanConsumer callback) throws RemoteException {
             executeMethodAsync(
                     () -> SatelliteImplBase.this
-                            .requestIsSatelliteEnabledForCarrier(simSlot, errorCallback, callback),
+                            .requestIsSatelliteEnabledForCarrier(simSlot, resultCallback, callback),
                     "requestIsSatelliteEnabledForCarrier");
         }
 
@@ -260,15 +260,15 @@
      *
      * @param listener The callback interface to handle satellite service indications.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     public void setSatelliteListener(@NonNull ISatelliteListener listener) {
         // stub implementation
@@ -281,20 +281,20 @@
      * @param enable True to enable satellite listening mode and false to disable.
      * @param timeout How long the satellite modem should wait for the next incoming page before
      *                disabling listening mode.
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     public void requestSatelliteListeningEnabled(boolean enable, int timeout,
-            @NonNull IIntegerConsumer errorCallback) {
+            @NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
@@ -302,10 +302,10 @@
      * Allow cellular modem scanning while satellite mode is on.
      * @param enabled  {@code true} to enable cellular modem while satellite mode is on
      * and {@code false} to disable
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      */
     public void enableCellularModemWhileSatelliteModeIsOn(boolean enabled,
-            @NonNull IIntegerConsumer errorCallback) {
+            @NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
@@ -316,42 +316,43 @@
      *
      * @param enableSatellite True to enable the satellite modem and false to disable.
      * @param enableDemoMode True to enable demo mode and false to disable.
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
-            @NonNull IIntegerConsumer errorCallback) {
+            @NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
     /**
      * Request to get whether the satellite modem is enabled.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
-     *                      This must only be sent when the result is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 whether the satellite modem is enabled.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive whether the satellite modem is enabled.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    public void requestIsSatelliteEnabled(@NonNull IIntegerConsumer errorCallback,
+    public void requestIsSatelliteEnabled(@NonNull IIntegerConsumer resultCallback,
             @NonNull IBooleanConsumer callback) {
         // stub implementation
     }
@@ -359,22 +360,23 @@
     /**
      * Request to get whether the satellite service is supported on the device.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
-     *                      This must only be sent when the result is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 whether the satellite service is supported on the device.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive whether the satellite service is supported on the device.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    public void requestIsSatelliteSupported(@NonNull IIntegerConsumer errorCallback,
+    public void requestIsSatelliteSupported(@NonNull IIntegerConsumer resultCallback,
             @NonNull IBooleanConsumer callback) {
         // stub implementation
     }
@@ -382,22 +384,23 @@
     /**
      * Request to get the SatelliteCapabilities of the satellite service.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
-     *                      This must only be sent when the result is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 the SatelliteCapabilities of the satellite service.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive the SatelliteCapabilities of the satellite service.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    public void requestSatelliteCapabilities(@NonNull IIntegerConsumer errorCallback,
+    public void requestSatelliteCapabilities(@NonNull IIntegerConsumer resultCallback,
             @NonNull ISatelliteCapabilitiesConsumer callback) {
         // stub implementation
     }
@@ -407,19 +410,19 @@
      * The satellite service should report the satellite pointing info via
      * ISatelliteListener#onSatellitePositionChanged as the user device/satellite moves.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    public void startSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) {
+    public void startSendingSatellitePointingInfo(@NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
@@ -427,19 +430,19 @@
      * User stopped pointing to the satellite.
      * The satellite service should stop reporting satellite pointing info to the framework.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    public void stopSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) {
+    public void stopSendingSatellitePointingInfo(@NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
@@ -452,23 +455,23 @@
      *              gateway.
      * @param provisionData Data from the provisioning app that can be used by provisioning
      *                      server
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:NETWORK_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:REQUEST_ABORTED
-     *   SatelliteError:NETWORK_TIMEOUT
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_ABORTED
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_TIMEOUT
      */
     public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
-            @NonNull IIntegerConsumer errorCallback) {
+            @NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
@@ -478,45 +481,46 @@
      * Once deprovisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report false.
      *
      * @param token The token of the device/subscription to be deprovisioned.
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:NETWORK_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:REQUEST_ABORTED
-     *   SatelliteError:NETWORK_TIMEOUT
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_ABORTED
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_TIMEOUT
      */
     public void deprovisionSatelliteService(@NonNull String token,
-            @NonNull IIntegerConsumer errorCallback) {
+            @NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
     /**
      * Request to get whether this device is provisioned with a satellite provider.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
-     *                      This must only be sent when the result is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 whether this device is provisioned with a satellite provider.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive whether this device is provisioned with a satellite provider.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    public void requestIsSatelliteProvisioned(@NonNull IIntegerConsumer errorCallback,
+    public void requestIsSatelliteProvisioned(@NonNull IIntegerConsumer resultCallback,
             @NonNull IBooleanConsumer callback) {
         // stub implementation
     }
@@ -526,24 +530,24 @@
      * The satellite service should check if there are any pending datagrams to be received over
      * satellite and report them via ISatelliteListener#onSatelliteDatagramsReceived.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:NETWORK_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:SATELLITE_ACCESS_BARRED
-     *   SatelliteError:NETWORK_TIMEOUT
-     *   SatelliteError:SATELLITE_NOT_REACHABLE
-     *   SatelliteError:NOT_AUTHORIZED
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_ACCESS_BARRED
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_TIMEOUT
+     *   SatelliteResult:SATELLITE_RESULT_NOT_REACHABLE
+     *   SatelliteResult:SATELLITE_RESULT_NOT_AUTHORIZED
      */
-    public void pollPendingSatelliteDatagrams(@NonNull IIntegerConsumer errorCallback) {
+    public void pollPendingSatelliteDatagrams(@NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
@@ -552,26 +556,26 @@
      *
      * @param datagram Datagram to send in byte format.
      * @param isEmergency Whether this is an emergency datagram.
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:NETWORK_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:REQUEST_ABORTED
-     *   SatelliteError:SATELLITE_ACCESS_BARRED
-     *   SatelliteError:NETWORK_TIMEOUT
-     *   SatelliteError:SATELLITE_NOT_REACHABLE
-     *   SatelliteError:NOT_AUTHORIZED
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_ABORTED
+     *   SatelliteResult:SATELLITE_RESULT_ACCESS_BARRED
+     *   SatelliteResult:SATELLITE_RESULT_NETWORK_TIMEOUT
+     *   SatelliteResult:SATELLITE_RESULT_NOT_REACHABLE
+     *   SatelliteResult:SATELLITE_RESULT_NOT_AUTHORIZED
      */
     public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency,
-            @NonNull IIntegerConsumer errorCallback) {
+            @NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
@@ -580,22 +584,23 @@
      * The satellite service should report the current satellite modem state via
      * ISatelliteListener#onSatelliteModemStateChanged.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
-     *                      This must only be sent when the result is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 the current satellite modem state.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive the current satellite modem state.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    public void requestSatelliteModemState(@NonNull IIntegerConsumer errorCallback,
+    public void requestSatelliteModemState(@NonNull IIntegerConsumer resultCallback,
             @NonNull IIntegerConsumer callback) {
         // stub implementation
     }
@@ -603,23 +608,24 @@
     /**
      * Request to get whether satellite communication is allowed for the current location.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
-     *                      This must only be sent when the result is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 whether satellite communication is allowed for the current location.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive whether satellite communication is allowed for the current location.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
     public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
-            @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) {
+            @NonNull IIntegerConsumer resultCallback, @NonNull IBooleanConsumer callback) {
         // stub implementation
     }
 
@@ -628,22 +634,23 @@
      * representing the duration in seconds after which the satellite will be visible.
      * This will return 0 if the satellite is currently visible.
      *
-     * @param errorCallback The callback to receive the error code result of the operation.
-     *                      This must only be sent when the result is not SatelliteError#ERROR_NONE.
-     * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
-     *                 the time after which the satellite will be visible.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *                       This must only be sent when the result is not
+     *                       SatelliteResult#SATELLITE_RESULT_SUCCESS.
+     * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
+     *                 receive the time after which the satellite will be visible.
      *
-     * Valid error codes returned:
-     *   SatelliteError:ERROR_NONE
-     *   SatelliteError:SERVICE_ERROR
-     *   SatelliteError:MODEM_ERROR
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
-     *   SatelliteError:NO_RESOURCES
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
      */
-    public void requestTimeForNextSatelliteVisibility(@NonNull IIntegerConsumer errorCallback,
+    public void requestTimeForNextSatelliteVisibility(@NonNull IIntegerConsumer resultCallback,
             @NonNull IIntegerConsumer callback) {
         // stub implementation
     }
@@ -658,25 +665,25 @@
      *
      * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
      * applied. The modem will use this information to determine the relevant carrier.
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      * @param carrierPlmnList The list of roaming PLMN used for connecting to satellite networks
      *                        supported by user subscription.
      * @param allSatellitePlmnList Modem should use the allSatellitePlmnList to identify satellite
      *                             PLMNs that are not supported by the carrier and make sure not to
      *                             attach to them.
      *
-     * Valid error codes returned:
-     *   SatelliteError:NONE
-     *   SatelliteError:INVALID_ARGUMENTS
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:MODEM_ERR
-     *   SatelliteError:NO_RESOURCES
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     * Valid result codes returned:
+     *   SatelliteResult:NONE
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:MODEM_ERR
+     *   SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
      */
     public void setSatellitePlmn(@NonNull int simLogicalSlotIndex,
             @NonNull List<String> carrierPlmnList, @NonNull List<String> allSatellitePlmnList,
-            @NonNull IIntegerConsumer errorCallback) {
+            @NonNull IIntegerConsumer resultCallback) {
         // stub implementation
     }
 
@@ -689,12 +696,12 @@
      * @param satelliteEnabled {@code true} to enable satellite, {@code false} to disable satellite.
      * @param callback {@code true} to enable satellite, {@code false} to disable satellite.
      *
-     * Valid errors returned:
-     *   SatelliteError:NONE
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:MODEM_ERR
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
      */
     public void setSatelliteEnabledForCarrier(@NonNull int simLogicalSlotIndex,
             @NonNull boolean satelliteEnabled, @NonNull IIntegerConsumer callback) {
@@ -707,18 +714,18 @@
      *
      * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
      * applied. The modem will use this information to determine the relevant carrier.
-     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param resultCallback The callback to receive the error code result of the operation.
      * @param callback {@code true} to satellite enabled, {@code false} to satellite disabled.
      *
-     * Valid errors returned:
-     *   SatelliteError:NONE
-     *   SatelliteError:INVALID_MODEM_STATE
-     *   SatelliteError:MODEM_ERR
-     *   SatelliteError:RADIO_NOT_AVAILABLE
-     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     * Valid result codes returned:
+     *   SatelliteResult:SATELLITE_RESULT_SUCCESS
+     *   SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
+     *   SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
+     *   SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
+     *   SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
      */
     public void requestIsSatelliteEnabledForCarrier(@NonNull int simLogicalSlotIndex,
-            @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) {
+            @NonNull IIntegerConsumer resultCallback, @NonNull IBooleanConsumer callback) {
         // stub implementation
     }
 }
diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt
index d1a68d4..241e691 100644
--- a/test-mock/api/current.txt
+++ b/test-mock/api/current.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android.test.mock {
 
   @Deprecated public class MockAccountManager {
diff --git a/test-mock/api/removed.txt b/test-mock/api/removed.txt
index 1496c35..fa2fbd2 100644
--- a/test-mock/api/removed.txt
+++ b/test-mock/api/removed.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android.test.mock {
 
   public class MockContext extends android.content.Context {
diff --git a/test-mock/api/system-current.txt b/test-mock/api/system-current.txt
index 9e022f0..2b5132e 100644
--- a/test-mock/api/system-current.txt
+++ b/test-mock/api/system-current.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android.test.mock {
 
   public class MockContext extends android.content.Context {
diff --git a/test-mock/api/system-removed.txt b/test-mock/api/system-removed.txt
index d802177..14191eb 100644
--- a/test-mock/api/system-removed.txt
+++ b/test-mock/api/system-removed.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index 35f076f..1752edc 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -1,4 +1,6 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
 package android.test.mock {
 
   public class MockContext extends android.content.Context {
diff --git a/test-mock/api/test-removed.txt b/test-mock/api/test-removed.txt
index d802177..14191eb 100644
--- a/test-mock/api/test-removed.txt
+++ b/test-mock/api/test-removed.txt
@@ -1 +1,3 @@
 // Signature format: 2.0
+// - add-additional-overrides=no
+// - migrating=Migration in progress see b/299366704
diff --git a/tests/BatteryStatsPerfTest/Android.bp b/tests/BatteryStatsPerfTest/Android.bp
index 5233a5b..c2a7015 100644
--- a/tests/BatteryStatsPerfTest/Android.bp
+++ b/tests/BatteryStatsPerfTest/Android.bp
@@ -27,7 +27,7 @@
     static_libs: [
         "androidx.test.rules",
         "apct-perftests-utils",
-        "truth-prebuilt",
+        "truth",
     ],
     platform_apis: true,
     certificate: "platform",
diff --git a/tests/BinaryTransparencyHostTest/Android.bp b/tests/BinaryTransparencyHostTest/Android.bp
index 615990f..38cb9869 100644
--- a/tests/BinaryTransparencyHostTest/Android.bp
+++ b/tests/BinaryTransparencyHostTest/Android.bp
@@ -30,7 +30,7 @@
         "compatibility-host-util",
     ],
     static_libs: [
-        "truth-prebuilt",
+        "truth",
     ],
     data: [
         ":BinaryTransparencyTestApp",
diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp
index c4faf7f..1fb73e2 100644
--- a/tests/BlobStoreTestUtils/Android.bp
+++ b/tests/BlobStoreTestUtils/Android.bp
@@ -22,12 +22,12 @@
 }
 
 java_library {
-  name: "BlobStoreTestUtils",
-  srcs: ["src/**/*.java"],
-  static_libs: [
-    "truth-prebuilt",
-    "androidx.test.uiautomator_uiautomator",
-    "androidx.test.ext.junit",
-  ],
-  sdk_version: "test_current",
+    name: "BlobStoreTestUtils",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "truth",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.ext.junit",
+    ],
+    sdk_version: "test_current",
 }
diff --git a/tests/ChoreographerTests/Android.bp b/tests/ChoreographerTests/Android.bp
index ca30267..5d49120 100644
--- a/tests/ChoreographerTests/Android.bp
+++ b/tests/ChoreographerTests/Android.bp
@@ -34,7 +34,7 @@
         "androidx.test.rules",
         "compatibility-device-util-axt",
         "com.google.android.material_material",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: [
         "libchoreographertests_jni",
diff --git a/tests/CtsSurfaceControlTestsStaging/Android.bp b/tests/CtsSurfaceControlTestsStaging/Android.bp
index 6809521..96e4a9e 100644
--- a/tests/CtsSurfaceControlTestsStaging/Android.bp
+++ b/tests/CtsSurfaceControlTestsStaging/Android.bp
@@ -37,7 +37,7 @@
         "compatibility-device-util-axt",
         "com.google.android.material_material",
         "SurfaceFlingerProperties",
-        "truth-prebuilt",
+        "truth",
     ],
     resource_dirs: ["src/main/res"],
     certificate: "platform",
diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.bp b/tests/DynamicCodeLoggerIntegrationTests/Android.bp
index 448d46f..3f2c808 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/Android.bp
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.bp
@@ -47,7 +47,7 @@
 
     static_libs: [
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
     ],
 
     compile_multilib: "both",
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index a2ae56e..82aa85d 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -236,7 +236,7 @@
     static_libs: [
         "flickerlib",
         "flickerlib-helpers",
-        "truth-prebuilt",
+        "truth",
         "app-helpers-core",
     ],
 }
@@ -255,7 +255,7 @@
         "flickerlib",
         "flickerlib-apphelpers",
         "flickerlib-helpers",
-        "truth-prebuilt",
+        "truth",
         "app-helpers-core",
         "wm-flicker-window-extensions",
     ],
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index c30786f..da51eff 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -17,6 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
+import android.content.Intent
 import android.media.session.MediaController
 import android.media.session.MediaSessionManager
 import android.tools.common.datatypes.Rect
@@ -267,6 +268,11 @@
     fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) =
         launchViaIntent(wmHelper)
 
+    fun changeAspectRatio() {
+        val intent = Intent("com.android.wm.shell.flicker.testapp.ASPECT_RATIO")
+        context.sendBroadcast(intent)
+    }
+
     fun clickEnterPipButton(wmHelper: WindowManagerStateHelper) {
         clickObject(ENTER_PIP_BUTTON_ID)
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
index cdb1d42..12eaad1 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
@@ -82,6 +82,8 @@
             "com.android.wm.shell.flicker.testapp.SWITCH_OFF";
     private static final String ACTION_SWITCH_ON = "com.android.wm.shell.flicker.testapp.SWITCH_ON";
     private static final String ACTION_CLEAR = "com.android.wm.shell.flicker.testapp.CLEAR";
+    private static final String ACTION_ASPECT_RATIO =
+            "com.android.wm.shell.flicker.testapp.ASPECT_RATIO";
 
     private final PictureInPictureParams.Builder mPipParamsBuilder =
             new PictureInPictureParams.Builder()
@@ -109,6 +111,9 @@
                     case ACTION_CLEAR:
                         mPipParamsBuilder.setActions(Collections.emptyList());
                         break;
+                    case ACTION_ASPECT_RATIO:
+                        mPipParamsBuilder.setAspectRatio(RATIO_TALL);
+                        break;
                     case ACTION_NO_OP:
                         return;
                     default:
@@ -190,6 +195,7 @@
         filter.addAction(ACTION_CLEAR);
         filter.addAction(ACTION_SET_REQUESTED_ORIENTATION);
         filter.addAction(ACTION_ENTER_PIP);
+        filter.addAction(ACTION_ASPECT_RATIO);
         registerReceiver(mBroadcastReceiver, filter);
 
         handleIntentExtra(getIntent());
diff --git a/tests/FsVerityTest/TEST_MAPPING b/tests/FsVerityTest/TEST_MAPPING
index 39944be..7d59d77 100644
--- a/tests/FsVerityTest/TEST_MAPPING
+++ b/tests/FsVerityTest/TEST_MAPPING
@@ -1,12 +1,7 @@
 {
-  "postsubmit": [
+  "presubmit": [
     {
       "name": "FsVerityTest"
-    },
-    // nextgen test only runs during postsubmit.
-    {
-      "name": "FsVerityTest",
-      "keywords": ["nextgen"]
     }
   ]
 }
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 365e00e..cf2d5d6 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -9,6 +9,10 @@
 
 android_test {
     name: "InputTests",
+    defaults: [
+        // For ExtendedMockito dependencies.
+        "modules-utils-testable-device-config-defaults",
+    ],
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
@@ -35,7 +39,7 @@
         "services.core.unboosted",
         "testables",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/tests/Input/src/com/android/server/input/FocusEventDebugViewTest.java b/tests/Input/src/com/android/server/input/FocusEventDebugViewTest.java
deleted file mode 100644
index 1b98887..0000000
--- a/tests/Input/src/com/android/server/input/FocusEventDebugViewTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2023 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.input;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.view.InputChannel;
-import android.view.InputDevice;
-import android.view.MotionEvent;
-import android.view.MotionEvent.PointerCoords;
-import android.view.MotionEvent.PointerProperties;
-import android.view.ViewConfiguration;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Build/Install/Run:
- * atest FocusEventDebugViewTest
- */
-@RunWith(AndroidJUnit4.class)
-public class FocusEventDebugViewTest {
-
-    private FocusEventDebugView mFocusEventDebugView;
-    private FocusEventDebugView.RotaryInputValueView mRotaryInputValueView;
-    private FocusEventDebugView.RotaryInputGraphView mRotaryInputGraphView;
-    private float mScaledVerticalScrollFactor;
-
-    @Before
-    public void setUp() throws Exception {
-        Context context = InstrumentationRegistry.getContext();
-        mScaledVerticalScrollFactor =
-                ViewConfiguration.get(context).getScaledVerticalScrollFactor();
-        InputManagerService mockService = mock(InputManagerService.class);
-        when(mockService.monitorInput(anyString(), anyInt()))
-                .thenReturn(InputChannel.openInputChannelPair("FocusEventDebugViewTest")[1]);
-
-        mRotaryInputValueView = new FocusEventDebugView.RotaryInputValueView(context);
-        mRotaryInputGraphView = new FocusEventDebugView.RotaryInputGraphView(context);
-        mFocusEventDebugView = new FocusEventDebugView(context, mockService,
-                () -> mRotaryInputValueView, () -> mRotaryInputGraphView);
-    }
-
-    @Test
-    public void startsRotaryInputValueViewWithDefaultValue() {
-        assertEquals("+0.0", mRotaryInputValueView.getText());
-    }
-
-    @Test
-    public void startsRotaryInputGraphViewWithDefaultFrameCenter() {
-        assertEquals(0, mRotaryInputGraphView.getFrameCenterPosition(), 0.01);
-    }
-
-    @Test
-    public void handleRotaryInput_updatesRotaryInputValueViewWithScrollValue() {
-        mFocusEventDebugView.handleUpdateShowRotaryInput(true);
-
-        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f));
-
-        assertEquals(String.format("+%.1f", 0.5f * mScaledVerticalScrollFactor),
-                mRotaryInputValueView.getText());
-    }
-
-    @Test
-    public void handleRotaryInput_translatesRotaryInputGraphViewWithHighScrollValue() {
-        mFocusEventDebugView.handleUpdateShowRotaryInput(true);
-
-        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(1000f));
-
-        assertTrue(mRotaryInputGraphView.getFrameCenterPosition() > 0);
-    }
-
-    @Test
-    public void updateActivityStatus_setsAndRemovesColorFilter() {
-        // It should not be active initially.
-        assertNull(mRotaryInputValueView.getBackground().getColorFilter());
-
-        mRotaryInputValueView.updateActivityStatus(true);
-        // It should be active after rotary input.
-        assertNotNull(mRotaryInputValueView.getBackground().getColorFilter());
-
-        mRotaryInputValueView.updateActivityStatus(false);
-        // It should not be active after waiting for mUpdateActivityStatusCallback.
-        assertNull(mRotaryInputValueView.getBackground().getColorFilter());
-    }
-
-    private MotionEvent createRotaryMotionEvent(float scrollAxisValue) {
-        PointerCoords pointerCoords = new PointerCoords();
-        pointerCoords.setAxisValue(MotionEvent.AXIS_SCROLL, scrollAxisValue);
-        PointerProperties pointerProperties = new PointerProperties();
-
-        return MotionEvent.obtain(
-                /* downTime */ 0,
-                /* eventTime */ 0,
-                /* action */ MotionEvent.ACTION_SCROLL,
-                /* pointerCount */ 1,
-                /* pointerProperties */ new PointerProperties[] {pointerProperties},
-                /* pointerCoords */ new PointerCoords[] {pointerCoords},
-                /* metaState */ 0,
-                /* buttonState */ 0,
-                /* xPrecision */ 0,
-                /* yPrecision */ 0,
-                /* deviceId */ 0,
-                /* edgeFlags */ 0,
-                /* source */ InputDevice.SOURCE_ROTARY_ENCODER,
-                /* flags */ 0
-        );
-    }
-}
diff --git a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index b6477510..44de6a6 100644
--- a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -32,11 +32,16 @@
 import android.os.test.TestLooper
 import android.platform.test.annotations.Presubmit
 import android.provider.Settings
+import android.util.proto.ProtoOutputStream
 import android.view.InputDevice
 import android.view.inputmethod.InputMethodInfo
 import android.view.inputmethod.InputMethodSubtype
 import androidx.test.core.R
 import androidx.test.core.app.ApplicationProvider
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.internal.os.KeyboardConfiguredProto
+import com.android.internal.util.FrameworkStatsLog
+import com.android.modules.utils.testing.ExtendedMockitoRule
 import org.junit.After
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotEquals
@@ -46,9 +51,9 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
+import org.mockito.ArgumentMatchers
 import org.mockito.Mock
 import org.mockito.Mockito
-import org.mockito.junit.MockitoJUnit
 import java.io.FileNotFoundException
 import java.io.FileOutputStream
 import java.io.IOException
@@ -95,16 +100,23 @@
         const val RECEIVER_NAME = "DummyReceiver"
         private const val ENGLISH_US_LAYOUT_NAME = "keyboard_layout_english_us"
         private const val ENGLISH_UK_LAYOUT_NAME = "keyboard_layout_english_uk"
+        private const val GERMAN_LAYOUT_NAME = "keyboard_layout_german"
         private const val VENDOR_SPECIFIC_LAYOUT_NAME = "keyboard_layout_vendorId:1,productId:1"
+        const val LAYOUT_TYPE_QWERTZ = 2
+        const val LAYOUT_TYPE_QWERTY = 1
+        const val LAYOUT_TYPE_DEFAULT = 0
     }
 
     private val ENGLISH_US_LAYOUT_DESCRIPTOR = createLayoutDescriptor(ENGLISH_US_LAYOUT_NAME)
     private val ENGLISH_UK_LAYOUT_DESCRIPTOR = createLayoutDescriptor(ENGLISH_UK_LAYOUT_NAME)
+    private val GERMAN_LAYOUT_DESCRIPTOR = createLayoutDescriptor(GERMAN_LAYOUT_NAME)
     private val VENDOR_SPECIFIC_LAYOUT_DESCRIPTOR =
         createLayoutDescriptor(VENDOR_SPECIFIC_LAYOUT_NAME)
 
-    @get:Rule
-    val rule = MockitoJUnit.rule()!!
+    @JvmField
+    @Rule
+    val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
+            .mockStatic(FrameworkStatsLog::class.java).build()!!
 
     @Mock
     private lateinit var iInputManager: IInputManager
@@ -145,7 +157,9 @@
             override fun finishWrite(fos: FileOutputStream?, success: Boolean) {}
         })
         testLooper = TestLooper()
-        keyboardLayoutManager = KeyboardLayoutManager(context, native, dataStore, testLooper.looper)
+        keyboardLayoutManager = Mockito.spy(
+            KeyboardLayoutManager(context, native, dataStore, testLooper.looper)
+        )
         setupInputDevices()
         setupBroadcastReceiver()
         setupIme()
@@ -698,7 +712,7 @@
             assertCorrectLayout(
                 keyboardDevice,
                 createImeSubtypeForLanguageTag("de"),
-                createLayoutDescriptor("keyboard_layout_german")
+                GERMAN_LAYOUT_DESCRIPTOR
             )
             assertCorrectLayout(
                 keyboardDevice,
@@ -763,13 +777,13 @@
             assertCorrectLayout(
                 keyboardDevice,
                 createImeSubtypeForLanguageTagAndLayoutType("de", "qwertz"),
-                createLayoutDescriptor("keyboard_layout_german")
+                GERMAN_LAYOUT_DESCRIPTOR
             )
             // Wrong layout type should match with language if provided layout type not available
             assertCorrectLayout(
                 keyboardDevice,
                 createImeSubtypeForLanguageTagAndLayoutType("de", "qwerty"),
-                createLayoutDescriptor("keyboard_layout_german")
+                GERMAN_LAYOUT_DESCRIPTOR
             )
             assertCorrectLayout(
                 keyboardDevice,
@@ -827,6 +841,100 @@
         }
     }
 
+    @Test
+    fun testConfigurationLogged_onInputDeviceAdded_VirtualKeyboardBasedSelection() {
+        val imeInfos = listOf(
+                KeyboardLayoutManager.ImeInfo(0, imeInfo,
+                        createImeSubtypeForLanguageTagAndLayoutType("de-Latn", "qwertz")))
+        Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping
+        NewSettingsApiFlag(true).use {
+            keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id)
+            ExtendedMockito.verify {
+                FrameworkStatsLog.write(
+                        ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
+                        ArgumentMatchers.anyBoolean(),
+                        ArgumentMatchers.eq(keyboardDevice.vendorId),
+                        ArgumentMatchers.eq(keyboardDevice.productId),
+                        ArgumentMatchers.eq(createByteArray(
+                                KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
+                                LAYOUT_TYPE_DEFAULT,
+                                GERMAN_LAYOUT_NAME,
+                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
+                                "de-Latn",
+                                LAYOUT_TYPE_QWERTZ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun testConfigurationLogged_onInputDeviceAdded_DeviceBasedSelection() {
+        val imeInfos = listOf(
+                KeyboardLayoutManager.ImeInfo(0, imeInfo,
+                        createImeSubtypeForLanguageTagAndLayoutType("de-Latn", "qwertz")))
+        Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping
+        NewSettingsApiFlag(true).use {
+            keyboardLayoutManager.onInputDeviceAdded(englishQwertyKeyboardDevice.id)
+            ExtendedMockito.verify {
+                FrameworkStatsLog.write(
+                        ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
+                        ArgumentMatchers.anyBoolean(),
+                        ArgumentMatchers.eq(englishQwertyKeyboardDevice.vendorId),
+                        ArgumentMatchers.eq(englishQwertyKeyboardDevice.productId),
+                        ArgumentMatchers.eq(createByteArray(
+                                "en",
+                                LAYOUT_TYPE_QWERTY,
+                                ENGLISH_US_LAYOUT_NAME,
+                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE,
+                                "de-Latn",
+                                LAYOUT_TYPE_QWERTZ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun testConfigurationLogged_onInputDeviceAdded_DefaultSelection() {
+        val imeInfos = listOf(KeyboardLayoutManager.ImeInfo(0, imeInfo, createImeSubtype()))
+        Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping
+        NewSettingsApiFlag(true).use {
+            keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id)
+            ExtendedMockito.verify {
+                FrameworkStatsLog.write(
+                        ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
+                        ArgumentMatchers.anyBoolean(),
+                        ArgumentMatchers.eq(keyboardDevice.vendorId),
+                        ArgumentMatchers.eq(keyboardDevice.productId),
+                        ArgumentMatchers.eq(createByteArray(
+                                KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
+                                LAYOUT_TYPE_DEFAULT,
+                                "Default",
+                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEFAULT,
+                                KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
+                                LAYOUT_TYPE_DEFAULT))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun testConfigurationNotLogged_onInputDeviceChanged() {
+        val imeInfos = listOf(KeyboardLayoutManager.ImeInfo(0, imeInfo, createImeSubtype()))
+        Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping
+        NewSettingsApiFlag(true).use {
+            keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id)
+            ExtendedMockito.verify({
+                FrameworkStatsLog.write(
+                        ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
+                        ArgumentMatchers.anyBoolean(),
+                        ArgumentMatchers.anyInt(),
+                        ArgumentMatchers.anyInt(),
+                        ArgumentMatchers.any(ByteArray::class.java)
+                )
+            }, Mockito.times(0))
+        }
+    }
+
     private fun assertCorrectLayout(
         device: InputDevice,
         imeSubtype: InputMethodSubtype,
@@ -842,18 +950,60 @@
     }
 
     private fun createImeSubtype(): InputMethodSubtype =
-        InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++).build()
+            createImeSubtypeForLanguageTagAndLayoutType(null, null)
 
     private fun createImeSubtypeForLanguageTag(languageTag: String): InputMethodSubtype =
-        InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++)
-            .setLanguageTag(languageTag).build()
+            createImeSubtypeForLanguageTagAndLayoutType(languageTag, null)
 
     private fun createImeSubtypeForLanguageTagAndLayoutType(
-        languageTag: String,
-        layoutType: String
-    ): InputMethodSubtype =
-        InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++)
-            .setPhysicalKeyboardHint(ULocale.forLanguageTag(languageTag), layoutType).build()
+            languageTag: String?,
+            layoutType: String?
+    ): InputMethodSubtype {
+        val builder = InputMethodSubtype.InputMethodSubtypeBuilder()
+                .setSubtypeId(nextImeSubtypeId++)
+                .setIsAuxiliary(false)
+                .setSubtypeMode("keyboard")
+        if (languageTag != null && layoutType != null) {
+            builder.setPhysicalKeyboardHint(ULocale.forLanguageTag(languageTag), layoutType)
+        } else if (languageTag != null) {
+            builder.setLanguageTag(languageTag)
+        }
+        return builder.build()
+    }
+
+    private fun createByteArray(
+            expectedLanguageTag: String, expectedLayoutType: Int, expectedLayoutName: String,
+            expectedCriteria: Int, expectedImeLanguageTag: String, expectedImeLayoutType: Int): ByteArray {
+        val proto = ProtoOutputStream()
+        val keyboardLayoutConfigToken = proto.start(
+                KeyboardConfiguredProto.RepeatedKeyboardLayoutConfig.KEYBOARD_LAYOUT_CONFIG)
+        proto.write(
+                KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LANGUAGE_TAG,
+                expectedLanguageTag
+        )
+        proto.write(
+                KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LAYOUT_TYPE,
+                expectedLayoutType
+        )
+        proto.write(
+                KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LAYOUT_NAME,
+                expectedLayoutName
+        )
+        proto.write(
+                KeyboardConfiguredProto.KeyboardLayoutConfig.LAYOUT_SELECTION_CRITERIA,
+                expectedCriteria
+        )
+        proto.write(
+                KeyboardConfiguredProto.KeyboardLayoutConfig.IME_LANGUAGE_TAG,
+                expectedImeLanguageTag
+        )
+        proto.write(
+                KeyboardConfiguredProto.KeyboardLayoutConfig.IME_LAYOUT_TYPE,
+                expectedImeLayoutType
+        )
+        proto.end(keyboardLayoutConfigToken);
+        return proto.bytes
+    }
 
     private fun hasLayout(layoutList: Array<KeyboardLayout>, layoutDesc: String): Boolean {
         for (kl in layoutList) {
diff --git a/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt b/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
index b39c932..33ff09b 100644
--- a/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
@@ -113,7 +113,7 @@
         )
         val event = builder.addLayoutSelection(
             createImeSubtype(1, ULocale.forLanguageTag("en-US"), "qwerty"),
-            KeyboardLayout(null, "English(US)(Qwerty)", null, 0, null, 0, 0, 0),
+            "English(US)(Qwerty)",
             KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
         ).addLayoutSelection(
             createImeSubtype(2, ULocale.forLanguageTag("en-US"), "azerty"),
@@ -121,7 +121,7 @@
             KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_USER
         ).addLayoutSelection(
             createImeSubtype(3, ULocale.forLanguageTag("en-US"), "qwerty"),
-            KeyboardLayout(null, "German", null, 0, null, 0, 0, 0),
+            "German",
             KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE
         ).setIsFirstTimeConfiguration(true).build()
 
@@ -184,7 +184,7 @@
         )
         val event = builder.addLayoutSelection(
             createImeSubtype(4, null, "qwerty"), // Default language tag
-            KeyboardLayout(null, "German", null, 0, null, 0, 0, 0),
+            "German",
             KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE
         ).build()
 
diff --git a/tests/Input/src/com/android/server/input/debug/FocusEventDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/FocusEventDebugViewTest.java
new file mode 100644
index 0000000..ae7fb3b
--- /dev/null
+++ b/tests/Input/src/com/android/server/input/debug/FocusEventDebugViewTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2023 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.input.debug;
+
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.input.InputManagerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build/Install/Run:
+ * atest FocusEventDebugViewTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class FocusEventDebugViewTest {
+
+    private FocusEventDebugView mFocusEventDebugView;
+    private RotaryInputValueView mRotaryInputValueView;
+    private RotaryInputGraphView mRotaryInputGraphView;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+        InputManagerService mockService = mock(InputManagerService.class);
+        when(mockService.monitorInput(anyString(), anyInt()))
+                .thenReturn(InputChannel.openInputChannelPair("FocusEventDebugViewTest")[1]);
+
+        mRotaryInputValueView = spy(new RotaryInputValueView(context));
+        mRotaryInputGraphView = spy(new RotaryInputGraphView(context));
+        mFocusEventDebugView = new FocusEventDebugView(context, mockService,
+                () -> mRotaryInputValueView, () -> mRotaryInputGraphView);
+    }
+
+    @Test
+    public void handleRotaryInput_sendsMotionEventWhenEnabled() {
+        mFocusEventDebugView.handleUpdateShowRotaryInput(true);
+
+        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f,  10L));
+
+        verify(mRotaryInputGraphView).addValue(0.5f, 10L);
+        verify(mRotaryInputValueView).updateValue(0.5f);
+    }
+
+    @Test
+    public void handleRotaryInput_doesNotSendMotionEventWhenDisabled() {
+        mFocusEventDebugView.handleUpdateShowRotaryInput(false);
+
+        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f, 10L));
+
+        verify(mRotaryInputGraphView, never()).addValue(anyFloat(), anyLong());
+        verify(mRotaryInputValueView, never()).updateValue(anyFloat());
+    }
+
+    private MotionEvent createRotaryMotionEvent(float scrollAxisValue, long eventTime) {
+        PointerCoords pointerCoords = new PointerCoords();
+        pointerCoords.setAxisValue(MotionEvent.AXIS_SCROLL, scrollAxisValue);
+        PointerProperties pointerProperties = new PointerProperties();
+
+        return MotionEvent.obtain(
+                /* downTime */ 0,
+                /* eventTime */ eventTime,
+                /* action */ MotionEvent.ACTION_SCROLL,
+                /* pointerCount */ 1,
+                /* pointerProperties */ new PointerProperties[] {pointerProperties},
+                /* pointerCoords */ new PointerCoords[] {pointerCoords},
+                /* metaState */ 0,
+                /* buttonState */ 0,
+                /* xPrecision */ 0,
+                /* yPrecision */ 0,
+                /* deviceId */ 0,
+                /* edgeFlags */ 0,
+                /* source */ InputDevice.SOURCE_ROTARY_ENCODER,
+                /* flags */ 0
+        );
+    }
+}
diff --git a/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java b/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java
new file mode 100644
index 0000000..af6ece4
--- /dev/null
+++ b/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023 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.input.debug;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build/Install/Run:
+ * atest RotaryInputGraphViewTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class RotaryInputGraphViewTest {
+
+    private RotaryInputGraphView mRotaryInputGraphView;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+
+        mRotaryInputGraphView = new RotaryInputGraphView(context);
+    }
+
+    @Test
+    public void startsWithDefaultFrameCenter() {
+        assertEquals(0, mRotaryInputGraphView.getFrameCenterPosition(), 0.01);
+    }
+
+    @Test
+    public void addValue_translatesRotaryInputGraphViewWithHighScrollValue() {
+        final float scrollAxisValue = 1000f;
+        final long eventTime = 0;
+
+        mRotaryInputGraphView.addValue(scrollAxisValue, eventTime);
+
+        assertTrue(mRotaryInputGraphView.getFrameCenterPosition() > 0);
+    }
+}
diff --git a/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java b/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java
new file mode 100644
index 0000000..e5e3852
--- /dev/null
+++ b/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2023 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.input.debug;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.Context;
+import android.view.ViewConfiguration;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+/**
+ * Build/Install/Run:
+ * atest RotaryInputValueViewTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class RotaryInputValueViewTest {
+
+    private final Locale mDefaultLocale = Locale.getDefault();
+
+    private RotaryInputValueView mRotaryInputValueView;
+    private float mScaledVerticalScrollFactor;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+        mScaledVerticalScrollFactor =
+                ViewConfiguration.get(context).getScaledVerticalScrollFactor();
+
+        mRotaryInputValueView = new RotaryInputValueView(context);
+    }
+
+    @Test
+    public void startsWithDefaultValue() {
+        assertEquals("+0.0", mRotaryInputValueView.getText().toString());
+    }
+
+    @Test
+    public void updateValue_updatesTextWithScrollValue() {
+        final float scrollAxisValue = 1000f;
+        final String expectedText = String.format(mDefaultLocale, "+%.1f",
+                scrollAxisValue * mScaledVerticalScrollFactor);
+
+        mRotaryInputValueView.updateValue(scrollAxisValue);
+
+        assertEquals(expectedText, mRotaryInputValueView.getText().toString());
+    }
+
+    @Test
+    public void updateActivityStatus_setsAndRemovesColorFilter() {
+        // It should not be active initially.
+        assertNull(mRotaryInputValueView.getBackground().getColorFilter());
+
+        mRotaryInputValueView.updateActivityStatus(true);
+        // It should be active after rotary input.
+        assertNotNull(mRotaryInputValueView.getBackground().getColorFilter());
+
+        mRotaryInputValueView.updateActivityStatus(false);
+        // It should not be active after waiting for mUpdateActivityStatusCallback.
+        assertNull(mRotaryInputValueView.getBackground().getColorFilter());
+    }
+}
diff --git a/tests/InputMethodStressTest/Android.bp b/tests/InputMethodStressTest/Android.bp
index 84845c6..58ceb3f 100644
--- a/tests/InputMethodStressTest/Android.bp
+++ b/tests/InputMethodStressTest/Android.bp
@@ -26,7 +26,7 @@
         "compatibility-device-util-axt",
         "platform-test-annotations",
         "platform-test-rules",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: [
         "general-tests",
diff --git a/tests/InputScreenshotTest/Android.bp b/tests/InputScreenshotTest/Android.bp
index eee486f..15aaa46 100644
--- a/tests/InputScreenshotTest/Android.bp
+++ b/tests/InputScreenshotTest/Android.bp
@@ -29,7 +29,7 @@
         "androidx.lifecycle_lifecycle-livedata-ktx",
         "androidx.lifecycle_lifecycle-runtime-compose",
         "androidx.navigation_navigation-compose",
-        "truth-prebuilt",
+        "truth",
         "androidx.compose.runtime_runtime",
         "androidx.test.core",
         "androidx.test.ext.junit",
@@ -47,7 +47,7 @@
         "services.core.unboosted",
         "testables",
         "testng",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
index ef45864..ddec8fa 100644
--- a/tests/Internal/Android.bp
+++ b/tests/Internal/Android.bp
@@ -19,7 +19,7 @@
         "junit",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
         "platform-test-annotations",
     ],
     java_resource_dirs: ["res"],
diff --git a/tests/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp
index 4e0b0a8..909ca59 100644
--- a/tests/LocalizationTest/Android.bp
+++ b/tests/LocalizationTest/Android.bp
@@ -34,7 +34,7 @@
         "androidx.test.ext.junit",
         "androidx.test.rules",
         "mockito-target-extended-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: [
         // For mockito extended
diff --git a/tests/MidiTests/Android.bp b/tests/MidiTests/Android.bp
index 254770d..fcacab3 100644
--- a/tests/MidiTests/Android.bp
+++ b/tests/MidiTests/Android.bp
@@ -31,7 +31,7 @@
         "mockito-target-inline-minus-junit4",
         "platform-test-annotations",
         "services.midi",
-        "truth-prebuilt",
+        "truth",
     ],
     jni_libs: ["libdexmakerjvmtiagent"],
     certificate: "platform",
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index 1e1dc84..e0e6c4c 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -32,7 +32,7 @@
         "androidx.test.rules",
         "services.core",
         "services.net",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.runner"],
     jni_libs: [
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index f0f9c4b..fd992cf 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -38,7 +38,7 @@
         "androidx.test.ext.junit",
         "mockito-target-minus-junit4",
         "testng",
-        "truth-prebuilt",
+        "truth",
         "platform-compat-test-rules",
     ],
 }
diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp
index 5f91f9d0..f6a41c2 100644
--- a/tests/PlatformCompatGating/test-rules/Android.bp
+++ b/tests/PlatformCompatGating/test-rules/Android.bp
@@ -29,7 +29,7 @@
     static_libs: [
         "junit",
         "androidx.test.core",
-        "truth-prebuilt",
-        "core-compat-test-rules"
+        "truth",
+        "core-compat-test-rules",
     ],
 }
diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp
index 38313f8..055d625 100644
--- a/tests/SurfaceViewBufferTests/Android.bp
+++ b/tests/SurfaceViewBufferTests/Android.bp
@@ -45,7 +45,7 @@
         "kotlinx-coroutines-android",
         "flickerlib",
         "flickerlib-trace_processor_shell",
-        "truth-prebuilt",
+        "truth",
         "cts-wm-util",
         "CtsSurfaceValidatorLib",
     ],
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
index bf12f42..d2ade34 100644
--- a/tests/TaskOrganizerTest/Android.bp
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -43,6 +43,6 @@
         "kotlinx-coroutines-android",
         "flickerlib",
         "flickerlib-trace_processor_shell",
-        "truth-prebuilt",
+        "truth",
     ],
 }
diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp
index 81ec265..b968e5d 100644
--- a/tests/TelephonyCommonTests/Android.bp
+++ b/tests/TelephonyCommonTests/Android.bp
@@ -32,11 +32,11 @@
     static_libs: [
         "mockito-target-extended",
         "androidx.test.rules",
-        "truth-prebuilt",
+        "truth",
         "platform-test-annotations",
         "androidx.core_core",
         "androidx.fragment_fragment",
-        "androidx.test.ext.junit"
+        "androidx.test.ext.junit",
     ],
 
     jni_libs: ["libdexmakerjvmtiagent"],
diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp
index c216bce..4e75a1d 100644
--- a/tests/TrustTests/Android.bp
+++ b/tests/TrustTests/Android.bp
@@ -28,7 +28,7 @@
         "flag-junit",
         "mockito-target-minus-junit4",
         "servicestests-utils",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.runner",
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index 9bfcc18..ddb3649 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -30,7 +30,7 @@
         "androidx.test.uiautomator_uiautomator",
         "compatibility-device-util-axt",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: [
         "general-tests",
diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp
index 97fbf5b..c02d8e9 100644
--- a/tests/UsbManagerTests/Android.bp
+++ b/tests/UsbManagerTests/Android.bp
@@ -31,7 +31,7 @@
         "androidx.test.rules",
         "mockito-target-inline-minus-junit4",
         "platform-test-annotations",
-        "truth-prebuilt",
+        "truth",
         "UsbManagerTestLib",
     ],
     jni_libs: ["libdexmakerjvmtiagent"],
diff --git a/tests/UsbManagerTests/lib/Android.bp b/tests/UsbManagerTests/lib/Android.bp
index 994484c..4e5a70fe 100644
--- a/tests/UsbManagerTests/lib/Android.bp
+++ b/tests/UsbManagerTests/lib/Android.bp
@@ -34,7 +34,7 @@
         "services.core",
         "services.net",
         "services.usb",
-        "truth-prebuilt",
+        "truth",
         "androidx.core_core",
     ],
     libs: [
diff --git a/tests/UsbTests/Android.bp b/tests/UsbTests/Android.bp
index c60c519..92c2711 100644
--- a/tests/UsbTests/Android.bp
+++ b/tests/UsbTests/Android.bp
@@ -34,7 +34,7 @@
         "services.core",
         "services.net",
         "services.usb",
-        "truth-prebuilt",
+        "truth",
         "UsbManagerTestLib",
     ],
     jni_libs: [
diff --git a/tests/componentalias/Android.bp b/tests/componentalias/Android.bp
index 01d34e4..39037f2 100644
--- a/tests/componentalias/Android.bp
+++ b/tests/componentalias/Android.bp
@@ -25,7 +25,7 @@
         "androidx.test.rules",
         "compatibility-device-util-axt",
         "mockito-target-extended-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: ["android.test.base"],
     srcs: [
diff --git a/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java b/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
index 6a6ab00..a43e1b0 100644
--- a/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
+++ b/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
@@ -21,15 +21,39 @@
 
 public class TestableFlagResolver implements SystemUiSystemPropertiesFlags.FlagResolver {
     private Map<String, Boolean> mOverrides = new HashMap<>();
+    private Map<String, Integer> mOverridesInt = new HashMap<>();
+    private Map<String, String> mOverridesString = new HashMap<>();
 
     @Override
     public boolean isEnabled(SystemUiSystemPropertiesFlags.Flag flag) {
         return mOverrides.getOrDefault(flag.mSysPropKey, flag.mDefaultValue);
     }
 
+    @Override
+    public int getIntValue(SystemUiSystemPropertiesFlags.Flag flag) {
+        return mOverridesInt.getOrDefault(flag.mSysPropKey, flag.mDefaultIntValue);
+    }
+
+    @Override
+    public String getStringValue(SystemUiSystemPropertiesFlags.Flag flag) {
+        return mOverridesString.getOrDefault(flag.mSysPropKey, flag.mDefaultStringValue);
+    }
+
     public TestableFlagResolver setFlagOverride(SystemUiSystemPropertiesFlags.Flag flag,
             boolean isEnabled) {
         mOverrides.put(flag.mSysPropKey, isEnabled);
         return this;
     }
+
+    public TestableFlagResolver setFlagOverride(SystemUiSystemPropertiesFlags.Flag flag,
+        int value) {
+        mOverridesInt.put(flag.mSysPropKey, value);
+        return this;
+    }
+
+    public TestableFlagResolver setFlagOverride(SystemUiSystemPropertiesFlags.Flag flag,
+        String value) {
+        mOverridesString.put(flag.mSysPropKey, value);
+        return this;
+    }
 }
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 7323b0f..977b276 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -220,6 +220,7 @@
     name: "aapt2-protos",
     tools: [":soong_zip"],
     srcs: [
+        "ApkInfo.proto",
         "Configuration.proto",
         "ResourcesInternal.proto",
         "ResourceMetadata.proto",
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 87da09a..8c644cf 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -49,16 +49,19 @@
     kDeprecated = 0x01,
     kSystemApi = 0x02,
     kTestApi = 0x04,
+    kFlaggedApi = 0x08,
   };
 
   StringPiece doc_str;
   uint32_t bit_mask;
   StringPiece annotation;
+  bool preserve_params;
 };
 
-static std::array<AnnotationRule, 2> sAnnotationRules = {{
-    {"@SystemApi", AnnotationRule::kSystemApi, "@android.annotation.SystemApi"},
-    {"@TestApi", AnnotationRule::kTestApi, "@android.annotation.TestApi"},
+static std::array<AnnotationRule, 3> sAnnotationRules = {{
+    {"@SystemApi", AnnotationRule::kSystemApi, "@android.annotation.SystemApi", true},
+    {"@TestApi", AnnotationRule::kTestApi, "@android.annotation.TestApi", false},
+    {"@FlaggedApi", AnnotationRule::kFlaggedApi, "@android.annotation.FlaggedApi", true},
 }};
 
 void AnnotationProcessor::AppendCommentLine(std::string comment) {
@@ -73,12 +76,11 @@
     std::string::size_type idx = comment.find(rule.doc_str.data());
     if (idx != std::string::npos) {
       // Captures all parameters associated with the specified annotation rule
-      // by matching the first pair of parantheses after the rule.
-      std::regex re(std::string(rule.doc_str) += "\\s*\\((.+)\\)");
+      // by matching the first pair of parentheses after the rule.
+      std::regex re(std::string(rule.doc_str).append(R"(\s*\((.+)\))"));
       std::smatch match_result;
       const bool is_match = std::regex_search(comment, match_result, re);
-      // We currently only capture and preserve parameters for SystemApi.
-      if (is_match && rule.bit_mask == AnnotationRule::kSystemApi) {
+      if (is_match && rule.preserve_params) {
         annotation_parameter_map_[rule.bit_mask] = match_result[1].str();
         comment.erase(comment.begin() + match_result.position(),
                       comment.begin() + match_result.position() + match_result.length());
diff --git a/tools/aapt2/java/AnnotationProcessor_test.cpp b/tools/aapt2/java/AnnotationProcessor_test.cpp
index 6bc8902..e98e96b 100644
--- a/tools/aapt2/java/AnnotationProcessor_test.cpp
+++ b/tools/aapt2/java/AnnotationProcessor_test.cpp
@@ -76,6 +76,36 @@
   EXPECT_THAT(annotations, HasSubstr("This is a system API"));
 }
 
+TEST(AnnotationProcessorTest, EmitsFlaggedApiAnnotationAndRemovesFromComment) {
+  AnnotationProcessor processor;
+  processor.AppendComment("@FlaggedApi This is a flagged API");
+
+  std::string annotations;
+  StringOutputStream out(&annotations);
+  Printer printer(&out);
+  processor.Print(&printer);
+  out.Flush();
+
+  EXPECT_THAT(annotations, HasSubstr("@android.annotation.FlaggedApi"));
+  EXPECT_THAT(annotations, Not(HasSubstr("@FlaggedApi")));
+  EXPECT_THAT(annotations, HasSubstr("This is a flagged API"));
+}
+
+TEST(AnnotationProcessorTest, EmitsFlaggedApiAnnotationParamsAndRemovesFromComment) {
+  AnnotationProcessor processor;
+  processor.AppendComment("@FlaggedApi (\"android.flags.my_flag\") This is a flagged API");
+
+  std::string annotations;
+  StringOutputStream out(&annotations);
+  Printer printer(&out);
+  processor.Print(&printer);
+  out.Flush();
+
+  EXPECT_THAT(annotations, HasSubstr("@android.annotation.FlaggedApi(\"android.flags.my_flag\")"));
+  EXPECT_THAT(annotations, Not(HasSubstr("@FlaggedApi")));
+  EXPECT_THAT(annotations, HasSubstr("This is a flagged API"));
+}
+
 TEST(AnnotationProcessorTest, EmitsTestApiAnnotationAndRemovesFromComment) {
   AnnotationProcessor processor;
   processor.AppendComment("@TestApi This is a test API");
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
index 33010ba..678e6ea 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
@@ -46,8 +46,11 @@
         }
         methodPolicy = policy
 
-        // TODO: Need to think about the realistic default behavior.
-        classPolicy = if (policy != FilterPolicy.Throw) policy else FilterPolicy.Remove
+        // If the default policy is "throw", we convert it to "keep" for classes and fields.
+        classPolicy = when (policy) {
+            FilterPolicy.Throw -> FilterPolicy.Keep
+            else -> policy
+        }
         fieldPolicy = classPolicy
     }
 
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
index 9c372ff..c6334c4 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
@@ -17,6 +17,8 @@
 
 import com.android.hoststubgen.HostStubGenErrors
 import com.android.hoststubgen.HostStubGenInternalException
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
 import com.android.hoststubgen.asm.isAnonymousInnerClass
 import com.android.hoststubgen.log
 import com.android.hoststubgen.asm.ClassNodes
@@ -81,6 +83,16 @@
             }
         }
 
+        // If we throw from the static initializer, the class would be useless, so we convert it
+        // "keep" instead.
+        if (methodName == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC &&
+            fallback.policy == FilterPolicy.Throw) {
+            // TODO Maybe show a warning?? But that'd be too noisy with --default-throw.
+            return FilterPolicy.Keep.withReason(
+                "'throw' on static initializer is handled as 'keep'" +
+                        " [original throw reason: ${fallback.reason}]")
+        }
+
         return fallback
     }
 }
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
index 57b6689..ce72a8e 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
@@ -79,7 +79,7 @@
             // StaticInitMerger will merge it with the existing one, if any.
             visitMethod(
                 Opcodes.ACC_PRIVATE or Opcodes.ACC_STATIC,
-                "<clinit>",
+                CLASS_INITIALIZER_NAME,
                 "()V",
                 null,
                 null
diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
index e7fb2de..b71e5c4 100644
--- a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
+++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
@@ -24,7 +24,7 @@
     ],
     static_libs: [
         "junit",
-        "truth-prebuilt",
+        "truth",
         "mockito",
 
         // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
index 05d6a43..f9dc305 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
@@ -104,7 +104,7 @@
     ],
     static_libs: [
         "junit",
-        "truth-prebuilt",
+        "truth",
 
         // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/
         "platform-test-annotations",
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 43ceec4..0761edc 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -372,7 +372,7 @@
   flags: (0x0021) ACC_PUBLIC, ACC_SUPER
   this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
   super_class: #x                         // java/lang/Object
-  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  interfaces: 0, fields: 1, methods: 1, attributes: 3
   public static boolean sInitialized;
     descriptor: Z
     flags: (0x0009) ACC_PUBLIC, ACC_STATIC
@@ -387,17 +387,6 @@
          x: ldc           #x                 // String Stub!
          x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
          x: athrow
-
-  static {};
-    descriptor: ()V
-    flags: (0x0008) ACC_STATIC
-    Code:
-      stack=3, locals=0, args_size=0
-         x: new           #x                 // class java/lang/RuntimeException
-         x: dup
-         x: ldc           #x                 // String Stub!
-         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
-         x: athrow
 }
 SourceFile: "TinyFrameworkClassWithInitializer.java"
 RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index 43ceec4..0761edc 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -372,7 +372,7 @@
   flags: (0x0021) ACC_PUBLIC, ACC_SUPER
   this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
   super_class: #x                         // java/lang/Object
-  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  interfaces: 0, fields: 1, methods: 1, attributes: 3
   public static boolean sInitialized;
     descriptor: Z
     flags: (0x0009) ACC_PUBLIC, ACC_STATIC
@@ -387,17 +387,6 @@
          x: ldc           #x                 // String Stub!
          x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
          x: athrow
-
-  static {};
-    descriptor: ()V
-    flags: (0x0008) ACC_STATIC
-    Code:
-      stack=3, locals=0, args_size=0
-         x: new           #x                 // class java/lang/RuntimeException
-         x: dup
-         x: ldc           #x                 // String Stub!
-         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
-         x: athrow
 }
 SourceFile: "TinyFrameworkClassWithInitializer.java"
 RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
index 079d2a8..8fcd2fb 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
@@ -15,3 +15,8 @@
 
 # Class load hook
 class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy	~com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+
+
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer stubclass
+  # Testing 'throw' on a static initializer. This should be handled as 'keep'.
+  method <clinit>	()V	 throw
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
index fd48646..722905f 100755
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
@@ -16,6 +16,10 @@
 
 source "${0%/*}"/../../common.sh
 
+#**********************************************************************************************
+#This script is broken because it relies on soong intermediate files, which seem to have moved.
+#**********************************************************************************************
+
 # This scripts run the "tiny-framework" test, but does most stuff from the command line, using
 # the native java and javac commands.
 # This is useful to
@@ -57,7 +61,7 @@
 
 test_compile_classpaths=(
   $SOONG_INT/external/junit/junit/android_common/combined/junit.jar
-  $SOONG_INT/prebuilts/tools/common/m2/truth-prebuilt/android_common/combined/truth-prebuilt.jar
+  $ANDROID_BUILD_TOP/out/target/common/obj/JAVA_LIBRARIES/truth-prebuilt_intermediates/classes.jar
 )
 
 test_runtime_classpaths=(
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
index 53cfdf6..01a690b 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
@@ -18,10 +18,14 @@
 import android.hosttest.annotation.HostSideTestClassLoadHook;
 import android.hosttest.annotation.HostSideTestWholeClassStub;
 
+
+// Note, policy-override-tiny-framework.txt hss an override on this class.
 @HostSideTestClassLoadHook(
         "com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
 @HostSideTestWholeClassStub
 public class TinyFrameworkClassWithInitializer {
+    // Note, this method has a 'throw' in the policy file, which is handled as a 'keep' (because
+    // it's a static initializer), so this won't show up in the stub jar.
     static {
         sInitialized = true;
     }
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
index 7600942..2e9cf42 100755
--- a/tools/hoststubgen/scripts/run-all-tests.sh
+++ b/tools/hoststubgen/scripts/run-all-tests.sh
@@ -33,7 +33,9 @@
 run ./hoststubgen/test-tiny-framework/diff-and-update-golden.sh
 
 run ./hoststubgen/test-framework/run-test-without-atest.sh
-run ./hoststubgen/test-tiny-framework/run-test-manually.sh
+
+#This script is broken because it relies on soong intermediate files, which seem to have moved.
+#run ./hoststubgen/test-tiny-framework/run-test-manually.sh
 run atest tiny-framework-dump-test
 run ./scripts/build-framework-hostside-jars-and-extract.sh
 
diff --git a/tools/processors/immutability/Android.bp b/tools/processors/immutability/Android.bp
index a7d69039..ecc283b 100644
--- a/tools/processors/immutability/Android.bp
+++ b/tools/processors/immutability/Android.bp
@@ -50,7 +50,7 @@
 
     static_libs: [
         "compile-testing-prebuilt",
-        "truth-prebuilt",
+        "truth",
         "junit",
         "kotlin-reflect",
         "ImmutabilityAnnotationProcessorHostLibrary",
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
index 7059c52..9c755b7 100644
--- a/tools/processors/intdef_mappings/Android.bp
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -38,7 +38,7 @@
 
     static_libs: [
         "compile-testing-prebuilt",
-        "truth-prebuilt",
+        "truth",
         "junit",
         "guava",
         "libintdef-annotation-processor",
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index 7a29969..5a0f742 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -40,7 +40,7 @@
         "frameworks-base-testutils",
         "guava",
         "mockito-target-minus-junit4",
-        "truth-prebuilt",
+        "truth",
     ],
 
     libs: [