Merge "Align mirroring bottom sheet to UX mocks" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 003b7f8..2d164f8 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -14,6 +14,7 @@
 
 aconfig_srcjars = [
     ":android.app.usage.flags-aconfig-java{.generated_srcjars}",
+    ":android.companion.flags-aconfig-java{.generated_srcjars}",
     ":android.content.pm.flags-aconfig-java{.generated_srcjars}",
     ":android.hardware.radio.flags-aconfig-java{.generated_srcjars}",
     ":android.nfc.flags-aconfig-java{.generated_srcjars}",
@@ -37,6 +38,7 @@
     ":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}",
@@ -243,6 +245,11 @@
     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",
@@ -287,6 +294,13 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+java_aconfig_library {
+    name: "android.content.pm.flags-aconfig-java-host",
+    aconfig_declarations: "android.content.pm.flags-aconfig",
+    host_supported: true,
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Media BetterTogether
 aconfig_declarations {
     name: "com.android.media.flags.bettertogether-aconfig",
@@ -311,6 +325,11 @@
     name: "android.permission.flags-aconfig-java",
     aconfig_declarations: "android.permission.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
+    min_sdk_version: "30",
+    apex_available: [
+        "com.android.permission",
+    ],
+
 }
 
 // Biometrics
@@ -340,6 +359,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",
@@ -424,7 +449,7 @@
     package: "android.service.autofill",
     srcs: [
         "services/autofill/bugfixes.aconfig",
-        "services/autofill/features.aconfig"
+        "services/autofill/features.aconfig",
     ],
 }
 
@@ -433,3 +458,16 @@
     aconfig_declarations: "android.service.autofill.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// Companion
+aconfig_declarations {
+    name: "android.companion.flags-aconfig",
+    package: "android.companion",
+    srcs: ["core/java/android/companion/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.companion.flags-aconfig-java",
+    aconfig_declarations: "android.companion.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/PREUPLOAD.cfg b/PREUPLOAD.cfg
index bded26a..015487d 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -25,6 +25,6 @@
 
 hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
 
-ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/packages/SystemUI/ktfmt_includes.txt ${PREUPLOAD_FILES}
+ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/ktfmt_includes.txt ${PREUPLOAD_FILES}
 
 ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES}
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/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/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
index 2b7438c..fdeb072 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
@@ -536,10 +536,13 @@
         static final String KEY_LAUNCH_TIME_ALLOWANCE_MS =
                 PC_CONSTANT_PREFIX + "launch_time_allowance_ms";
 
-        private static final long DEFAULT_LAUNCH_TIME_THRESHOLD_MS = 7 * HOUR_IN_MILLIS;
-        private static final long DEFAULT_LAUNCH_TIME_ALLOWANCE_MS = 20 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_LAUNCH_TIME_THRESHOLD_MS = HOUR_IN_MILLIS;
+        private static final long DEFAULT_LAUNCH_TIME_ALLOWANCE_MS = 30 * MINUTE_IN_MILLIS;
 
-        /** How much time each app will have to run jobs within their standby bucket window. */
+        /**
+         * The earliest amount of time before the next estimated app launch time that we may choose
+         * to run a prefetch job for the app.
+         */
         public long LAUNCH_TIME_THRESHOLD_MS = DEFAULT_LAUNCH_TIME_THRESHOLD_MS;
 
         /**
diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp
index 8d8fc12..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,
 }
@@ -197,7 +161,7 @@
     name: "framework-docs-default",
     sdk_version: "none",
     system_modules: "none",
-    libs: framework_docs_only_libs + [
+    libs: [
         "stub-annotations",
         "unsupportedappusage",
     ],
@@ -236,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"],
@@ -303,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: [
@@ -397,7 +283,6 @@
 
 droiddoc {
     name: "ds-docs-kt",
-    defaults: ["framework-dokka-docs-default"],
     srcs: [
         ":framework-doc-stubs",
     ],
@@ -476,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/StubLibraries.bp b/api/StubLibraries.bp
index 2d9c988..fa4bc0f 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -438,6 +438,26 @@
     full_api_surface_stub: "android_module_lib_stubs_current_full.from-text",
 }
 
+// This module generates a stub jar that is a union of the test and module lib
+// non-updatable api contributions. Modules should not depend on the stub jar
+// generated from this module, as this module is strictly used for hiddenapi only.
+java_api_library {
+    name: "android-non-updatable.stubs.test_module_lib",
+    api_surface: "module_lib",
+    api_contributions: [
+        "api-stubs-docs-non-updatable.api.contribution",
+        "system-api-stubs-docs-non-updatable.api.contribution",
+        "test-api-stubs-docs-non-updatable.api.contribution",
+        "module-lib-api-stubs-docs-non-updatable.api.contribution",
+    ],
+    defaults: ["android-non-updatable_from_text_defaults"],
+    full_api_surface_stub: "android_test_module_lib_stubs_current.from-text",
+
+    // This module is only used for hiddenapi, and other modules should not
+    // depend on this module.
+    visibility: ["//visibility:private"],
+}
+
 java_defaults {
     name: "android_stubs_dists_default",
     dist: {
@@ -757,6 +777,30 @@
 }
 
 java_api_library {
+    name: "android_test_module_lib_stubs_current.from-text",
+    api_surface: "module-lib",
+    defaults: [
+        "android_stubs_current_contributions",
+        "android_system_stubs_current_contributions",
+        "android_test_stubs_current_contributions",
+        "android_module_lib_stubs_current_contributions",
+    ],
+    libs: [
+        "android_module_lib_stubs_current_full.from-text",
+        "stub-annotations",
+    ],
+    api_contributions: [
+        "test-api-stubs-docs-non-updatable.api.contribution",
+    ],
+
+    // This module is only used to build android-non-updatable.stubs.test_module_lib
+    // and other modules should not depend on this module.
+    visibility: [
+        "//visibility:private",
+    ],
+}
+
+java_api_library {
     name: "android_system_server_stubs_current.from-text",
     api_surface: "system-server",
     api_contributions: [
diff --git a/api/javadoc-lint-baseline b/api/javadoc-lint-baseline
index 8713126..d1821d9 100644
--- a/api/javadoc-lint-baseline
+++ b/api/javadoc-lint-baseline
@@ -8,9 +8,12 @@
 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]
@@ -83,35 +86,12 @@
 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]
@@ -209,57 +189,12 @@
 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/telecom/Call.java:94: lint: unable to parse link/see tag: #playDtmfTone(char [101]
-android/telecom/CallControl.java:163: lint: Unresolved link/see tag "android.telecom.CallStreamingService CallStreamingService" in android.telecom.CallControl [101]
-android/telecom/CallControlCallback.java:63: lint: Unresolved link/see tag "android.telecom.CallAttributes.CallType" in android.telecom.CallControlCallback [101]
-android/telecom/PhoneAccountSuggestion.java:17: lint: Unresolved link/see tag "android.telecom.PhoneAccountSuggestionService PhoneAccountSuggestionService" in android.telecom.PhoneAccountSuggestion [101]
-android/telephony/CarrierConfigManager.java:2934: lint: Unresolved link/see tag "android.telephony.TelephonyManager.PremiumCapability TelephonyManager.PremiumCapability" in android.telephony.CarrierConfigManager [101]
-android/telephony/CarrierConfigManager.java:4020: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101]
-android/telephony/CarrierConfigManager.java:4108: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101]
-android/telephony/CarrierConfigManager.java:3920: lint: Unresolved link/see tag "android.telephony.ims.SipDelegateManager" in android.telephony.CarrierConfigManager.Ims [101]
-android/telephony/CarrierConfigManager.java:4001: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101]
-android/telephony/CarrierConfigManager.java:4089: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101]
-android/telephony/NetworkRegistrationInfo.java:131: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.NetworkRegistrationInfo [101]
-android/telephony/PhoneStateListener.java:293: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.PhoneStateListener [101]
-android/telephony/PhoneStateListener.java:544: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.PhoneStateListener [101]
-android/telephony/SubscriptionManager.java:1385: lint: Unresolved link/see tag "Build.VERSION_CODES.P" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [101]
-android/telephony/SubscriptionManager.java:1385: lint: Unresolved link/see tag "Build.VERSION_CODES.V" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [101]
-android/telephony/SubscriptionPlan.java:134: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.SubscriptionPlan [101]
-android/telephony/SubscriptionPlan.java:288: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.SubscriptionPlan.Builder [101]
-android/telephony/TelephonyCallback.java:113: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.TelephonyCallback.CallDisconnectCauseListener [101]
-android/telephony/TelephonyManager.java:2544: lint: Unresolved link/see tag "android.telephony.TelephonyManager.CarrierRestrictionStatus CarrierRestrictionStatus" in android.telephony.TelephonyManager [101]
-android/telephony/TelephonyManager.java:2841: lint: Unresolved link/see tag "android.telephony.TelephonyManager.SetOpportunisticSubscriptionResult TelephonyManager.SetOpportunisticSubscriptionResult" in android.telephony.TelephonyManager [101]
-android/telephony/TelephonyManager.java:3273: lint: Unresolved link/see tag "android.telephony.TelephonyManager.PurchasePremiumCapabilityResult PurchasePremiumCapabilityResult" in android.telephony.TelephonyManager [101]
-android/telephony/TelephonyManager.java:3989: lint: Unresolved link/see tag "android.telephony.TelephonyManager.MobileDataPolicy MobileDataPolicy" in android.telephony.TelephonyManager [101]
-android/telephony/data/ApnSetting.java:39: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV4() DataCallResponse#getMtuV4()" in android.telephony.data.ApnSetting [101]
-android/telephony/data/ApnSetting.java:50: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV6() DataCallResponse#getMtuV6()" in android.telephony.data.ApnSetting [101]
-android/telephony/data/ApnSetting.java:597: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV4() DataCallResponse#getMtuV4()" in android.telephony.data.ApnSetting.Builder [101]
-android/telephony/data/ApnSetting.java:611: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV6() DataCallResponse#getMtuV6()" in android.telephony.data.ApnSetting.Builder [101]
-android/telephony/euicc/EuiccManager.java:331: lint: Unresolved link/see tag "android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE" in android.telephony.euicc.EuiccManager [101]
-android/telephony/ims/ImsMmTelManager.java:117: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.ImsMmTelManager [101]
-android/telephony/ims/ImsRcsManager.java:43: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.ImsRcsManager [101]
-android/telephony/ims/ProvisioningManager.java:102: lint: Unresolved link/see tag "android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability MmTelFeature.MmTelCapabilities.MmTelCapability" in android.telephony.ims.ProvisioningManager [101]
-android/telephony/ims/ProvisioningManager.java:102: lint: Unresolved link/see tag "android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.ims.ProvisioningManager [101]
-android/telephony/ims/ProvisioningManager.java:136: lint: Unresolved link/see tag "android.telephony.ims.ImsRcsManager.RcsImsCapabilityFlag ImsRcsManager.RcsImsCapabilityFlag" in android.telephony.ims.ProvisioningManager [101]
-android/telephony/ims/RegistrationManager.java:21: lint: Unresolved link/see tag "android.telephony.ims.feature.ImsFeature ImsFeature" in android.telephony.ims.RegistrationManager [101]
-android/telephony/ims/RegistrationManager.java:24: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.RegistrationManager [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]
@@ -291,78 +226,7 @@
 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]
 
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101]
-com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101]
-com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101]
-com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101]
-com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101]
-com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101]
-com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101]
-com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101]
-com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101]
-com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101]
-com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101]
-com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101]
-com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101]
-com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101]
-com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101]
-com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101]
-com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101]
-com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [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]
@@ -370,13 +234,10 @@
 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/telephony/TelephonyRegistryManager.java:242: lint: Unresolved link/see tag "#listenFromListener" 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]
@@ -393,11 +254,7 @@
 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/telephony/SubscriptionManager.java:1370: lint: Unresolved link/see tag "Build.VERSION_CODES.Q" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [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]
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 d037c31..9c7dc17 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 {
@@ -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;
@@ -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
@@ -28562,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";
@@ -31971,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
@@ -32382,7 +32392,7 @@
     method public void addData(@NonNull String, @Nullable byte[], int);
     method public void addFile(@NonNull String, @NonNull java.io.File, int) throws java.io.IOException;
     method public void addText(@NonNull String, @NonNull String);
-    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_LOGS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.DropBoxManager.Entry getNextEntry(String, long);
+    method @Nullable @RequiresPermission(allOf={"android.permission.READ_DROPBOX_DATA", android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.DropBoxManager.Entry getNextEntry(String, long);
     method public boolean isTagEnabled(String);
     field public static final String ACTION_DROPBOX_ENTRY_ADDED = "android.intent.action.DROPBOX_ENTRY_ADDED";
     field public static final String EXTRA_DROPPED_COUNT = "android.os.extra.DROPPED_COUNT";
@@ -41554,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();
@@ -44213,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
@@ -44322,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();
@@ -44338,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
@@ -44553,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);
@@ -45339,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";
@@ -46672,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);
   }
 
@@ -47199,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);
   }
 
@@ -47912,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();
   }
@@ -53115,6 +53129,7 @@
     method @Nullable public abstract android.view.View getCurrentFocus();
     method @NonNull public abstract android.view.View getDecorView();
     method public static int getDefaultFeatures(android.content.Context);
+    method @FlaggedApi("com.android.graphics.hwui.flags.limited_hdr") public float getDesiredHdrHeadroom();
     method public android.transition.Transition getEnterTransition();
     method public android.transition.Transition getExitTransition();
     method protected final int getFeatures();
@@ -53184,6 +53199,7 @@
     method public abstract void setDecorCaptionShade(int);
     method public void setDecorFitsSystemWindows(boolean);
     method protected void setDefaultWindowFormat(int);
+    method @FlaggedApi("com.android.graphics.hwui.flags.limited_hdr") public void setDesiredHdrHeadroom(@FloatRange(from=0.0f, to=10000.0) float);
     method public void setDimAmount(float);
     method public void setElevation(float);
     method public void setEnterTransition(android.transition.Transition);
@@ -53533,6 +53549,7 @@
     method public int describeContents();
     method public int getBlurBehindRadius();
     method public int getColorMode();
+    method @FlaggedApi("com.android.graphics.hwui.flags.limited_hdr") public float getDesiredHdrHeadroom();
     method public int getFitInsetsSides();
     method public int getFitInsetsTypes();
     method public final CharSequence getTitle();
@@ -53542,6 +53559,7 @@
     method public void setBlurBehindRadius(@IntRange(from=0) int);
     method public void setCanPlayMoveAnimation(boolean);
     method public void setColorMode(int);
+    method @FlaggedApi("com.android.graphics.hwui.flags.limited_hdr") public void setDesiredHdrHeadroom(@FloatRange(from=0.0f, to=10000.0f) float);
     method public void setFitInsetsIgnoringVisibility(boolean);
     method public void setFitInsetsSides(int);
     method public void setFitInsetsTypes(int);
@@ -54652,7 +54670,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();
@@ -54679,7 +54696,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);
@@ -54700,10 +54716,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);
@@ -55155,12 +55167,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..500a12c 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 {
@@ -6,9 +8,7 @@
     field public static final String CONTROL_AUTOMOTIVE_GNSS = "android.permission.CONTROL_AUTOMOTIVE_GNSS";
     field public static final String GET_INTENT_SENDER_INTENT = "android.permission.GET_INTENT_SENDER_INTENT";
     field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
-    field public static final String MANAGE_REMOTE_AUTH = "android.permission.MANAGE_REMOTE_AUTH";
     field public static final String USE_COMPANION_TRANSPORTS = "android.permission.USE_COMPANION_TRANSPORTS";
-    field public static final String USE_REMOTE_AUTH = "android.permission.USE_REMOTE_AUTH";
   }
 
 }
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 5a4be65..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 {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a99eeb0..7dcc7b2 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";
@@ -652,7 +655,6 @@
     field public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO = "android:receive_ambient_trigger_audio";
     field public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
     field public static final String OPSTR_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO = "android:receive_explicit_user_interaction_audio";
-    field public static final String OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO = "android:receive_sandbox_trigger_audio";
     field public static final String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
     field public static final String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
     field public static final String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
@@ -3209,7 +3211,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);
@@ -4529,7 +4531,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 +9607,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 +9707,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 +9774,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 +13230,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 +13711,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 +16681,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 db751a4..eeddeb2 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 {
@@ -28,7 +30,6 @@
     field public static final String MANAGE_APP_OPS_MODES = "android.permission.MANAGE_APP_OPS_MODES";
     field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
     field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
-    field public static final String MANAGE_REMOTE_AUTH = "android.permission.MANAGE_REMOTE_AUTH";
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final String MANAGE_TOAST_RATE_LIMITING = "android.permission.MANAGE_TOAST_RATE_LIMITING";
     field public static final String MODIFY_HDR_CONVERSION_MODE = "android.permission.MODIFY_HDR_CONVERSION_MODE";
@@ -56,7 +57,6 @@
     field public static final String TEST_INPUT_METHOD = "android.permission.TEST_INPUT_METHOD";
     field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
-    field public static final String USE_REMOTE_AUTH = "android.permission.USE_REMOTE_AUTH";
     field public static final String WRITE_ALLOWLISTED_DEVICE_CONFIG = "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG";
     field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
@@ -840,7 +840,7 @@
 
 package android.companion {
 
-  public static final class AssociationInfo.Builder {
+  @FlaggedApi("android.companion.new_association_builder") public static final class AssociationInfo.Builder {
     ctor public AssociationInfo.Builder(int, int, @NonNull String);
     ctor public AssociationInfo.Builder(@NonNull android.companion.AssociationInfo);
     method @NonNull public android.companion.AssociationInfo build();
@@ -1181,6 +1181,7 @@
     method @Nullable public CharSequence getLabel(@NonNull android.content.Context);
     method @Nullable public android.graphics.drawable.Drawable getServiceIcon(@NonNull android.content.Context);
     method @NonNull public android.content.pm.ServiceInfo getServiceInfo();
+    method @FlaggedApi("android.credentials.flags.settings_activity_enabled") @Nullable public CharSequence getSettingsActivity();
     method @Nullable public CharSequence getSettingsSubtitle();
     method @NonNull public boolean hasCapability(@NonNull String);
     method public boolean isEnabled();
@@ -1903,7 +1904,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 +1916,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 +2613,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 +2958,6 @@
     method @Deprecated public boolean isBound();
   }
 
-  public class NotificationRankingUpdate implements android.os.Parcelable {
-    method public final boolean isFdNotNullAndClosed();
-  }
-
 }
 
 package android.service.quickaccesswallet {
@@ -3188,7 +3187,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 +3280,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 +3407,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 +3568,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 +3626,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/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..17637df 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,22 +2253,22 @@
     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
      */
-    @SystemApi
     public static final String OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO =
             "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 +2380,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 +2812,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/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/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/app/servertransaction/WindowStateResizeItem.java b/core/java/android/app/servertransaction/WindowStateResizeItem.java
new file mode 100644
index 0000000..9828133
--- /dev/null
+++ b/core/java/android/app/servertransaction/WindowStateResizeItem.java
@@ -0,0 +1,193 @@
+/*
+ * 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.app.servertransaction;
+
+import static android.view.Display.INVALID_DISPLAY;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ClientTransactionHandler;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.util.MergedConfiguration;
+import android.view.IWindow;
+import android.view.InsetsState;
+import android.window.ClientWindowFrames;
+
+import java.util.Objects;
+
+/**
+ * Message to deliver window resize info.
+ * @hide
+ */
+public class WindowStateResizeItem extends ClientTransactionItem {
+
+    private IWindow mWindow;
+    private ClientWindowFrames mFrames;
+    private boolean mReportDraw;
+    private MergedConfiguration mConfiguration;
+    private InsetsState mInsetsState;
+    private boolean mForceLayout;
+    private boolean mAlwaysConsumeSystemBars;
+    private int mDisplayId;
+    private int mSyncSeqId;
+    private boolean mDragResizing;
+
+    @Override
+    public void execute(@NonNull ClientTransactionHandler client,
+            @NonNull PendingTransactionActions pendingActions) {
+        try {
+            mWindow.resized(mFrames, mReportDraw, mConfiguration, mInsetsState, mForceLayout,
+                    mAlwaysConsumeSystemBars, mDisplayId, mSyncSeqId, mDragResizing);
+        } catch (RemoteException e) {
+            // Should be a local call.
+            throw new RuntimeException(e);
+        }
+    }
+
+    // ObjectPoolItem implementation
+
+    private WindowStateResizeItem() {}
+
+    /** Obtains an instance initialized with provided params. */
+    public static WindowStateResizeItem obtain(@NonNull IWindow window,
+            @NonNull ClientWindowFrames frames, boolean reportDraw,
+            @NonNull MergedConfiguration configuration, @NonNull InsetsState insetsState,
+            boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
+            boolean dragResizing) {
+        WindowStateResizeItem instance =
+                ObjectPool.obtain(WindowStateResizeItem.class);
+        if (instance == null) {
+            instance = new WindowStateResizeItem();
+        }
+        instance.mWindow = requireNonNull(window);
+        instance.mFrames = requireNonNull(frames);
+        instance.mReportDraw = reportDraw;
+        instance.mConfiguration = requireNonNull(configuration);
+        instance.mInsetsState = requireNonNull(insetsState);
+        instance.mForceLayout = forceLayout;
+        instance.mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
+        instance.mDisplayId = displayId;
+        instance.mSyncSeqId = syncSeqId;
+        instance.mDragResizing = dragResizing;
+
+        return instance;
+    }
+
+    @Override
+    public void recycle() {
+        mWindow = null;
+        mFrames = null;
+        mReportDraw = false;
+        mConfiguration = null;
+        mInsetsState = null;
+        mForceLayout = false;
+        mAlwaysConsumeSystemBars = false;
+        mDisplayId = INVALID_DISPLAY;
+        mSyncSeqId = -1;
+        mDragResizing = false;
+        ObjectPool.recycle(this);
+    }
+
+    // Parcelable implementation
+
+    /** Writes to Parcel. */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeStrongBinder(mWindow.asBinder());
+        dest.writeTypedObject(mFrames, flags);
+        dest.writeBoolean(mReportDraw);
+        dest.writeTypedObject(mConfiguration, flags);
+        dest.writeTypedObject(mInsetsState, flags);
+        dest.writeBoolean(mForceLayout);
+        dest.writeBoolean(mAlwaysConsumeSystemBars);
+        dest.writeInt(mDisplayId);
+        dest.writeInt(mSyncSeqId);
+        dest.writeBoolean(mDragResizing);
+    }
+
+    /** Reads from Parcel. */
+    private WindowStateResizeItem(@NonNull Parcel in) {
+        mWindow = IWindow.Stub.asInterface(in.readStrongBinder());
+        mFrames = in.readTypedObject(ClientWindowFrames.CREATOR);
+        mReportDraw = in.readBoolean();
+        mConfiguration = in.readTypedObject(MergedConfiguration.CREATOR);
+        mInsetsState = in.readTypedObject(InsetsState.CREATOR);
+        mForceLayout = in.readBoolean();
+        mAlwaysConsumeSystemBars = in.readBoolean();
+        mDisplayId = in.readInt();
+        mSyncSeqId = in.readInt();
+        mDragResizing = in.readBoolean();
+    }
+
+    public static final @NonNull Creator<WindowStateResizeItem> CREATOR = new Creator<>() {
+        public WindowStateResizeItem createFromParcel(@NonNull Parcel in) {
+            return new WindowStateResizeItem(in);
+        }
+
+        public WindowStateResizeItem[] newArray(int size) {
+            return new WindowStateResizeItem[size];
+        }
+    };
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final WindowStateResizeItem other = (WindowStateResizeItem) o;
+        return Objects.equals(mWindow, other.mWindow)
+                && Objects.equals(mFrames, other.mFrames)
+                && mReportDraw == other.mReportDraw
+                && Objects.equals(mConfiguration, other.mConfiguration)
+                && Objects.equals(mInsetsState, other.mInsetsState)
+                && mForceLayout == other.mForceLayout
+                && mAlwaysConsumeSystemBars == other.mAlwaysConsumeSystemBars
+                && mDisplayId == other.mDisplayId
+                && mSyncSeqId == other.mSyncSeqId
+                && mDragResizing == other.mDragResizing;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + Objects.hashCode(mWindow);
+        result = 31 * result + Objects.hashCode(mFrames);
+        result = 31 * result + (mReportDraw ? 1 : 0);
+        result = 31 * result + Objects.hashCode(mConfiguration);
+        result = 31 * result + Objects.hashCode(mInsetsState);
+        result = 31 * result + (mForceLayout ? 1 : 0);
+        result = 31 * result + (mAlwaysConsumeSystemBars ? 1 : 0);
+        result = 31 * result + mDisplayId;
+        result = 31 * result + mSyncSeqId;
+        result = 31 * result + (mDragResizing ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "WindowStateResizeItem{window=" + mWindow
+                + ", reportDrawn=" + mReportDraw
+                + ", configuration=" + mConfiguration
+                + "}";
+    }
+}
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 083fa00..6393c45 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -15,6 +15,7 @@
  */
 package android.companion;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -412,6 +413,7 @@
      *
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_NEW_ASSOCIATION_BUILDER)
     @TestApi
     public static final class Builder {
         private final int mId;
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index 03e75e9..570ecaa 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -161,16 +161,16 @@
     public static final int DEVICE_EVENT_BT_DISCONNECTED = 3;
 
     /**
-     * A companion app for a {@link AssociationInfo#isSelfManaged() self-managed} device will
-     * receive the callback {@link #onDeviceEvent(AssociationInfo, int)} if it reports that a
-     * device has appeared on its own.
+     * A companion app for a self-managed device will receive the callback
+     * {@link #onDeviceEvent(AssociationInfo, int)} if it reports that a device has appeared on its
+     * own.
      */
     public static final int DEVICE_EVENT_SELF_MANAGED_APPEARED = 4;
 
     /**
-     * A companion app for a {@link AssociationInfo#isSelfManaged() self-managed} device will
-     * receive the callback {@link #onDeviceEvent(AssociationInfo, int)} if it reports that a
-     * device has disappeared on its own.
+     * A companion app for a self-managed device will receive the callback
+     * {@link #onDeviceEvent(AssociationInfo, int)} if it reports that a device has disappeared on
+     * its own.
      */
     public static final int DEVICE_EVENT_SELF_MANAGED_DISAPPEARED = 5;
 
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
new file mode 100644
index 0000000..b9e5609
--- /dev/null
+++ b/core/java/android/companion/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.companion"
+
+flag {
+    name: "new_association_builder"
+    namespace: "companion"
+    description: "Controls if the new Builder is exposed to test apis."
+    bug: "296251481"
+}
\ No newline at end of file
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index ce883cd..93a3e78 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -33,9 +33,6 @@
  *
  * <p>Read-only device representation exposing the properties of an existing virtual device.
  *
- * <p class="note">Not to be confused with {@link VirtualDeviceManager.VirtualDevice}, which is used
- * by the virtual device creator and allows them to manage the device.
- *
  * @see VirtualDeviceManager#registerVirtualDeviceListener
  */
 public final class VirtualDevice implements Parcelable {
@@ -113,14 +110,13 @@
      * <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;
     }
 
     /**
      * Returns the name of the virtual device (optionally) provided during its creation.
-     *
-     * @see VirtualDeviceParams.Builder#setName(String)
      */
     public @Nullable String getName() {
         return mName;
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 39800f7..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();
         }
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/virtual/sensor/VirtualSensorDirectChannelWriter.java b/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java
index bf78dd0..b9451a7 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java
@@ -46,15 +46,15 @@
  * <pre>
  * VirtualSensorDirectChannelWriter writer = new VirtualSensorDirectChannelWriter();
  * VirtualSensorDirectChannelCallback callback = new VirtualSensorDirectChannelCallback() {
- *     @Override
+ *     {@literal @}Override
  *     public void onDirectChannelCreated(int channelHandle, SharedMemory sharedMemory) {
  *         writer.addChannel(channelHandle, sharedMemory);
  *     }
- *     @Override
+ *     {@literal @}Override
  *     public void onDirectChannelDestroyed(int channelHandle);
  *         writer.removeChannel(channelHandle);
  *     }
- *     @Override
+ *     {@literal @}Override
  *     public void onDirectChannelConfigured(int channelHandle, VirtualSensor sensor, int rateLevel,
  *             int reportToken)
  *         if (!writer.configureChannel(channelHandle, sensor, rateLevel, reportToken)) {
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/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 36e0529..3fbcd70 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -30,6 +30,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /**
  * Content capture options for a given package.
@@ -119,7 +124,10 @@
                 /* enableReceiver= */ false,
                 new ContentProtectionOptions(
                         /* enableReceiver= */ false,
-                        /* bufferSize= */ 0),
+                        /* bufferSize= */ 0,
+                        /* requiredGroups= */ Collections.emptyList(),
+                        /* optionalGroups= */ Collections.emptyList(),
+                        /* optionalGroupsThreshold= */ 0),
                 /* whitelistedComponents= */ null);
     }
 
@@ -141,9 +149,7 @@
                 logHistorySize,
                 ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
                 ContentCaptureManager.DEFAULT_ENABLE_CONTENT_CAPTURE_RECEIVER,
-                new ContentProtectionOptions(
-                        ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER,
-                        ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE),
+                new ContentProtectionOptions(),
                 whitelistedComponents);
     }
 
@@ -183,9 +189,7 @@
                 ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE,
                 ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
                 ContentCaptureManager.DEFAULT_ENABLE_CONTENT_CAPTURE_RECEIVER,
-                new ContentProtectionOptions(
-                        ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER,
-                        ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE),
+                new ContentProtectionOptions(),
                 whitelistedComponents);
     }
 
@@ -386,9 +390,58 @@
          */
         public final int bufferSize;
 
-        public ContentProtectionOptions(boolean enableReceiver, int bufferSize) {
+        /**
+         * The list of required groups of strings to match.
+         *
+         * @hide
+         */
+        @NonNull public final List<List<String>> requiredGroups;
+
+        /**
+         * The list of optional groups of strings to match.
+         *
+         * @hide
+         */
+        @NonNull public final List<List<String>> optionalGroups;
+
+        /**
+         * The minimal number of optional groups that have to be matched. This is the threshold
+         * value and comparison is done with greater than or equals.
+         *
+         * @hide
+         */
+        public final int optionalGroupsThreshold;
+
+        /**
+         * Empty constructor with default values.
+         *
+         * @hide
+         */
+        public ContentProtectionOptions() {
+            this(
+                    ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER,
+                    ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE,
+                    ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_REQUIRED_GROUPS,
+                    ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS,
+                    ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD);
+        }
+
+        /**
+         * Full primary constructor.
+         *
+         * @hide
+         */
+        public ContentProtectionOptions(
+                boolean enableReceiver,
+                int bufferSize,
+                @NonNull List<List<String>> requiredGroups,
+                @NonNull List<List<String>> optionalGroups,
+                int optionalGroupsThreshold) {
             this.enableReceiver = enableReceiver;
             this.bufferSize = bufferSize;
+            this.requiredGroups = requiredGroups;
+            this.optionalGroups = optionalGroups;
+            this.optionalGroupsThreshold = optionalGroupsThreshold;
         }
 
         @Override
@@ -398,7 +451,14 @@
                     .append("enableReceiver=")
                     .append(enableReceiver)
                     .append(", bufferSize=")
-                    .append(bufferSize);
+                    .append(bufferSize)
+                    .append(", requiredGroupsSize=")
+                    .append(requiredGroups.size())
+                    .append(", optionalGroupsSize=")
+                    .append(optionalGroups.size())
+                    .append(", optionalGroupsThreshold=")
+                    .append(optionalGroupsThreshold);
+
             return stringBuilder.append(']').toString();
         }
 
@@ -407,17 +467,50 @@
             pw.print(enableReceiver);
             pw.print(", bufferSize=");
             pw.print(bufferSize);
+            pw.print(", requiredGroupsSize=");
+            pw.print(requiredGroups.size());
+            pw.print(", optionalGroupsSize=");
+            pw.print(optionalGroups.size());
+            pw.print(", optionalGroupsThreshold=");
+            pw.print(optionalGroupsThreshold);
         }
 
-        private void writeToParcel(Parcel parcel) {
+        private void writeToParcel(@NonNull Parcel parcel) {
             parcel.writeBoolean(enableReceiver);
             parcel.writeInt(bufferSize);
+            writeGroupsToParcel(requiredGroups, parcel);
+            writeGroupsToParcel(optionalGroups, parcel);
+            parcel.writeInt(optionalGroupsThreshold);
         }
 
-        private static ContentProtectionOptions createFromParcel(Parcel parcel) {
+        @NonNull
+        private static ContentProtectionOptions createFromParcel(@NonNull Parcel parcel) {
             boolean enableReceiver = parcel.readBoolean();
             int bufferSize = parcel.readInt();
-            return new ContentProtectionOptions(enableReceiver, bufferSize);
+            List<List<String>> requiredGroups = createGroupsFromParcel(parcel);
+            List<List<String>> optionalGroups = createGroupsFromParcel(parcel);
+            int optionalGroupsThreshold = parcel.readInt();
+            return new ContentProtectionOptions(
+                    enableReceiver,
+                    bufferSize,
+                    requiredGroups,
+                    optionalGroups,
+                    optionalGroupsThreshold);
+        }
+
+        private static void writeGroupsToParcel(
+                @NonNull List<List<String>> groups, @NonNull Parcel parcel) {
+            parcel.writeInt(groups.size());
+            groups.forEach(parcel::writeStringList);
+        }
+
+        @NonNull
+        private static List<List<String>> createGroupsFromParcel(@NonNull Parcel parcel) {
+            int size = parcel.readInt();
+            return IntStream.range(0, size)
+                    .mapToObj(i -> new ArrayList<String>())
+                    .peek(parcel::readStringList)
+                    .collect(Collectors.toUnmodifiableList());
         }
     }
 }
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/om/OverlayIdentifier.java b/core/java/android/content/om/OverlayIdentifier.java
index f256372..30875aa 100644
--- a/core/java/android/content/om/OverlayIdentifier.java
+++ b/core/java/android/content/om/OverlayIdentifier.java
@@ -39,7 +39,6 @@
  * -->
  *
  * @see OverlayInfo#getOverlayIdentifier()
- * @see OverlayManagerTransaction.Builder#unregisterFabricatedOverlay(OverlayIdentifier)
  */
 @DataClass(genConstructor = false, genBuilder = false, genHiddenBuilder = false,
         genEqualsHashCode = true, genToString = false)
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index ff1c088..2e89856 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -385,7 +385,6 @@
      * <p>The return value of this function can be used to unregister the related overlay.
      *
      * @return an identifier representing the current overlay.
-     * @see OverlayManagerTransaction.Builder#unregisterFabricatedOverlay(OverlayIdentifier)
      */
     @Override
     @NonNull
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 0fcc72a1..ed965b3 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -50,7 +50,7 @@
  *   <li>register overlays
  *   <li>unregister overlays
  *   <li>execute multiple operations in one commitment by calling {@link
- *       OverlayManagerTransaction#commit()}
+ *       #commit(OverlayManagerTransaction)}
  * </ul>
  *
  * @see OverlayManagerTransaction
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 036a4eb..aefa55f 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1185,8 +1185,8 @@
      * <p>For {@link android.view.View#getWindowVisibleDisplayFrame} and
      * {@link android.view.View}#getWindowDisplayFrame this sandboxing is happening indirectly
      * through
-     * {@link android.view.ViewRootImpl}#getWindowVisibleDisplayFrame,
-     * {@link android.view.ViewRootImpl}#getDisplayFrame respectively.
+     * {@code android.view.ViewRootImpl#getWindowVisibleDisplayFrame},
+     * {@code android.view.ViewRootImpl#getDisplayFrame} respectively.
      *
      * <p>Some applications assume that they occupy the whole screen and therefore use the display
      * coordinates in their calculations as if an activity is  positioned in the top-left corner of
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..d837aae 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2730,8 +2730,8 @@
          * Sets the state of permissions for the package at installation.
          * <p/>
          * Granting any runtime permissions require the
-         * {@link android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS
-         * INSTALL_GRANT_RUNTIME_PERMISSIONS} permission to be held by the caller. Revoking runtime
+         * {@code android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS}
+         * permission to be held by the caller. Revoking runtime
          * permissions is not allowed, even during app update sessions.
          * <p/>
          * Holders without the permission are allowed to change the following special permissions:
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8fbe50c3..45338bb 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -9878,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
@@ -9888,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/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 65f56f6..9869179 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -132,11 +132,6 @@
      * the {@link android.R.attr#foregroundServiceType} attribute.
      * Data(photo, file, account) upload/download, backup/restore, import/export, fetch,
      * transfer over network between device and cloud.
-     *
-     * <p class="note">
-     * Use the {@link android.app.job.JobInfo.Builder#setDataTransfer} API for data transfers
-     * that can be deferred until conditions are ideal for the app or device.
-     * </p>
      */
     @RequiresPermission(
             value = Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC,
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..b2cc070 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 {
@@ -42,3 +43,10 @@
     description: "Feature flag to enable the feature to retrieve package info without installation."
     bug: "269149275"
 }
+
+flag {
+    name: "use_art_service_v2"
+    namespace: "package_manager_service"
+    description: "Feature flag to enable the features that rely on new ART Service APIs that are in the VIC version of the ART module."
+    bug: "304741685"
+}
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/content/pm/verify/domain/DomainVerificationUserState.java b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
index 1e60abb..7ada946 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
@@ -231,7 +231,7 @@
     }
 
     /**
-     * Mapping of domain host to state, as defined by {@link DomainState}.
+     * Mapping of domain host to state, as defined by the {@code DOMAIN_STATE_*} constants
      */
     @DataClass.Generated.Member
     public @NonNull Map<String,Integer> getHostToStateMap() {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ed22284..1b37092 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2210,8 +2210,7 @@
      *
      * <p>The best practices is to obtain metrics from
      * {@link WindowManager#getCurrentWindowMetrics()} for window bounds. The value obtained from
-     * this API may be wrong if {@link Context#getResources()} is from
-     * non-{@link android.annotation.UiContext}.
+     * this API may be wrong if {@link Context#getResources()} is not from a {@code UiContext}.
      * For example, use the {@link DisplayMetrics} obtained from {@link Application#getResources()}
      * to build {@link android.app.Activity} UI elements especially when the
      * {@link android.app.Activity} is in the multi-window mode or on the secondary {@link Display}.
diff --git a/core/java/android/credentials/CreateCredentialException.java b/core/java/android/credentials/CreateCredentialException.java
index c344004..8f07d19 100644
--- a/core/java/android/credentials/CreateCredentialException.java
+++ b/core/java/android/credentials/CreateCredentialException.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.Activity;
+import android.content.Context;
 import android.os.CancellationSignal;
 import android.os.OutcomeReceiver;
 
@@ -28,8 +28,8 @@
 
 /**
  * Represents an error encountered during the
- * {@link CredentialManager#createCredential(CreateCredentialRequest,
- * Activity, CancellationSignal, Executor, OutcomeReceiver)} operation.
+ * {@link CredentialManager#createCredential(Context, CreateCredentialRequest,
+ * CancellationSignal, Executor, OutcomeReceiver)} operation.
  */
 public class CreateCredentialException extends Exception {
     /**
@@ -41,7 +41,7 @@
 
     /**
      * The error type value for when no create options are available from any provider(s),
-     * for the given {@link CredentialManager#createCredential(CreateCredentialRequest, Activity,
+     * for the given {@link CredentialManager#createCredential(Context, CreateCredentialRequest,
      * CancellationSignal, Executor, OutcomeReceiver)} request.
      */
     @NonNull
diff --git a/core/java/android/credentials/CredentialDescription.java b/core/java/android/credentials/CredentialDescription.java
index db71624..755e659 100644
--- a/core/java/android/credentials/CredentialDescription.java
+++ b/core/java/android/credentials/CredentialDescription.java
@@ -155,8 +155,7 @@
     }
 
     /**
-     * {@link CredentialDescription#mType} and
-     * {@link CredentialDescription#mSupportedElementKeys} are enough for hashing. Constructor
+     * {@link #getType()} and {@link #getSupportedElementKeys()} are enough for hashing. Constructor
      * enforces {@link CredentialEntry} to have the same type and
      * {@link android.app.slice.Slice} contained by the entry can not be hashed.
      */
@@ -166,8 +165,7 @@
     }
 
     /**
-     * {@link CredentialDescription#mType} and
-     * {@link CredentialDescription#mSupportedElementKeys} are enough for equality check.
+     * {@link #getType()} and {@link #getSupportedElementKeys()} are enough for equality check.
      */
     @Override
     public boolean equals(Object obj) {
diff --git a/core/java/android/credentials/CredentialProviderInfo.java b/core/java/android/credentials/CredentialProviderInfo.java
index 95ca011..8503072 100644
--- a/core/java/android/credentials/CredentialProviderInfo.java
+++ b/core/java/android/credentials/CredentialProviderInfo.java
@@ -16,12 +16,14 @@
 
 package android.credentials;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ServiceInfo;
+import android.credentials.flags.Flags;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -42,6 +44,7 @@
     @NonNull private final List<String> mCapabilities = new ArrayList<>();
     @Nullable private final CharSequence mOverrideLabel;
     @Nullable private CharSequence mSettingsSubtitle = null;
+    @Nullable private CharSequence mSettingsActivity = null;
     private final boolean mIsSystemProvider;
     private final boolean mIsEnabled;
     private final boolean mIsPrimary;
@@ -59,6 +62,7 @@
         mIsEnabled = builder.mIsEnabled;
         mIsPrimary = builder.mIsPrimary;
         mOverrideLabel = builder.mOverrideLabel;
+        mSettingsActivity = builder.mSettingsActivity;
     }
 
     /** Returns true if the service supports the given {@code credentialType}, false otherwise. */
@@ -104,10 +108,7 @@
         return mIsEnabled;
     }
 
-    /**
-     * Returns whether the provider is set as primary by the user.
-     *
-     */
+    /** Returns whether the provider is set as primary by the user. */
     public boolean isPrimary() {
         return mIsPrimary;
     }
@@ -118,6 +119,18 @@
         return mSettingsSubtitle;
     }
 
+    /**
+     * Returns the settings activity.
+     *
+     * @hide
+     */
+    @Nullable
+    @TestApi
+    @FlaggedApi(Flags.FLAG_SETTINGS_ACTIVITY_ENABLED)
+    public CharSequence getSettingsActivity() {
+        return mSettingsActivity;
+    }
+
     /** Returns the component name for the service. */
     @NonNull
     public ComponentName getComponentName() {
@@ -133,6 +146,7 @@
         dest.writeBoolean(mIsPrimary);
         TextUtils.writeToParcel(mOverrideLabel, dest, flags);
         TextUtils.writeToParcel(mSettingsSubtitle, dest, flags);
+        TextUtils.writeToParcel(mSettingsActivity, dest, flags);
     }
 
     @Override
@@ -161,6 +175,9 @@
                 + "settingsSubtitle="
                 + mSettingsSubtitle
                 + ", "
+                + "settingsActivity="
+                + mSettingsActivity
+                + ", "
                 + "capabilities="
                 + String.join(",", mCapabilities)
                 + "}";
@@ -174,6 +191,7 @@
         mIsPrimary = in.readBoolean();
         mOverrideLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mSettingsSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mSettingsActivity = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
     }
 
     public static final @NonNull Parcelable.Creator<CredentialProviderInfo> CREATOR =
@@ -196,6 +214,7 @@
         @NonNull private List<String> mCapabilities = new ArrayList<>();
         private boolean mIsSystemProvider = false;
         @Nullable private CharSequence mSettingsSubtitle = null;
+        @Nullable private CharSequence mSettingsActivity = null;
         private boolean mIsEnabled = false;
         private boolean mIsPrimary = false;
         @Nullable private CharSequence mOverrideLabel = null;
@@ -231,6 +250,16 @@
             return this;
         }
 
+        /**
+         * Sets the settings activity.
+         *
+         * @hide
+         */
+        public @NonNull Builder setSettingsActivity(@Nullable CharSequence settingsActivity) {
+            mSettingsActivity = settingsActivity;
+            return this;
+        }
+
         /** Sets a list of capabilities this provider service can support. */
         public @NonNull Builder addCapabilities(@NonNull List<String> capabilities) {
             mCapabilities.addAll(capabilities);
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/GetCredentialException.java b/core/java/android/credentials/GetCredentialException.java
index 720c53b..0421d1f 100644
--- a/core/java/android/credentials/GetCredentialException.java
+++ b/core/java/android/credentials/GetCredentialException.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.Activity;
+import android.content.Context;
 import android.os.CancellationSignal;
 import android.os.OutcomeReceiver;
 
@@ -28,8 +28,8 @@
 
 /**
  * Represents an error encountered during the
- * {@link CredentialManager#getCredential(GetCredentialRequest,
- * Activity, CancellationSignal, Executor, OutcomeReceiver)} operation.
+ * {@link CredentialManager#getCredential(Context, GetCredentialRequest,
+ * CancellationSignal, Executor, OutcomeReceiver)} operation.
  */
 public class GetCredentialException extends Exception {
     /**
@@ -41,7 +41,7 @@
 
     /**
      * The error type value for when no credential is found available for the given {@link
-     * CredentialManager#getCredential(GetCredentialRequest, Activity, CancellationSignal,
+     * CredentialManager#getCredential(Context, GetCredentialRequest, CancellationSignal,
      * Executor, OutcomeReceiver)} request.
      */
     @NonNull
diff --git a/core/java/android/credentials/PrepareGetCredentialResponse.java b/core/java/android/credentials/PrepareGetCredentialResponse.java
index 056b18a..212f571 100644
--- a/core/java/android/credentials/PrepareGetCredentialResponse.java
+++ b/core/java/android/credentials/PrepareGetCredentialResponse.java
@@ -22,7 +22,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.IntentSender;
@@ -36,7 +35,7 @@
 /**
  * A response object that prefetches user app credentials and provides metadata about them. It can
  * then be used to issue the full credential retrieval flow via the
- * {@link CredentialManager#getCredential(PendingGetCredentialHandle, Activity, CancellationSignal,
+ * {@link CredentialManager#getCredential(Context, PendingGetCredentialHandle, CancellationSignal,
  * Executor, OutcomeReceiver)} method to perform the remaining flows such as consent collection
  * and credential selection, to officially retrieve a credential.
  */
@@ -44,7 +43,7 @@
 
     /**
      * A handle that represents a pending get-credential operation. Pass this handle to {@link
-     * CredentialManager#getCredential(PendingGetCredentialHandle, Activity, CancellationSignal,
+     * CredentialManager#getCredential(Context, PendingGetCredentialHandle, CancellationSignal,
      * Executor, OutcomeReceiver)} to perform the remaining flows to officially retrieve a
      * credential.
      */
@@ -144,7 +143,7 @@
 
     /**
      * Returns a handle that represents this pending get-credential operation. Pass this handle to
-     * {@link CredentialManager#getCredential(PendingGetCredentialHandle, Activity,
+     * {@link CredentialManager#getCredential(Context, PendingGetCredentialHandle,
      * CancellationSignal, Executor, OutcomeReceiver)} to perform the remaining flows to officially
      * retrieve a credential.
      */
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/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 82694ee..9c05dfc 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -537,6 +537,24 @@
     }
 
     /**
+     * Listens for biometric prompt status, i.e., if it is being shown or idle.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void registerBiometricPromptStatusListener(
+            IBiometricPromptStatusListener callback) {
+        if (mService != null) {
+            try {
+                mService.registerBiometricPromptStatusListener(callback);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "registerBiometricPromptOnKeyguardCallback(): Service not connected");
+        }
+    }
+
+    /**
      * Requests all {@link Authenticators.Types#BIOMETRIC_STRONG} sensors to have their
      * authenticatorId invalidated for the specified user. This happens when enrollments have been
      * added on devices with multiple biometric sensors.
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
index 151f819..6ac1efb 100644
--- a/core/java/android/hardware/biometrics/CryptoObject.java
+++ b/core/java/android/hardware/biometrics/CryptoObject.java
@@ -114,8 +114,8 @@
     }
 
     /**
-     * Get {@link PresentationSession} object.
-     * @return {@link PresentationSession} object or null if this doesn't contain one.
+     * 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() {
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index c2e5c0b..8eede47 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -17,6 +17,7 @@
 package android.hardware.biometrics;
 
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.biometrics.IBiometricPromptStatusListener;
 import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
@@ -63,6 +64,9 @@
     // Register callback for when keyguard biometric eligibility changes.
     void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
 
+    // Register callback to check biometric prompt status.
+    void registerBiometricPromptStatusListener(IBiometricPromptStatusListener callback);
+
     // Requests all BIOMETRIC_STRONG sensors to have their authenticatorId invalidated for the
     // specified user. This happens when enrollments have been added on devices with multiple
     // biometric sensors.
diff --git a/core/java/android/hardware/biometrics/IBiometricPromptStatusListener.aidl b/core/java/android/hardware/biometrics/IBiometricPromptStatusListener.aidl
new file mode 100644
index 0000000..7a0f438
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IBiometricPromptStatusListener.aidl
@@ -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 android.hardware.biometrics;
+
+/**
+ * Communication channel to propagate biometric prompt status. Implementation of this interface
+ * should be registered in BiometricService#registerBiometricPromptStatusListener.
+ * @hide
+ */
+oneway interface IBiometricPromptStatusListener {
+    void onBiometricPromptShowing();
+    void onBiometricPromptIdle();
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 18c8d1b..36606a1 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -17,6 +17,7 @@
 package android.hardware.biometrics;
 
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.biometrics.IBiometricPromptStatusListener;
 import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IInvalidationCallback;
@@ -68,6 +69,10 @@
     @EnforcePermission("USE_BIOMETRIC_INTERNAL")
     void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
 
+    // Register a callback for biometric prompt status on keyguard.
+    @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+    void registerBiometricPromptStatusListener(IBiometricPromptStatusListener callback);
+
     // Notify BiometricService when <Biometric>Service is ready to start the prepared client.
     // Client lifecycle is still managed in <Biometric>Service.
     @EnforcePermission("USE_BIOMETRIC_INTERNAL")
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/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 1307dfc..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;
@@ -1826,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/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index cf35460..109d6b2 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -17,7 +17,7 @@
 package android.os;
 
 import static android.Manifest.permission.PACKAGE_USAGE_STATS;
-import static android.Manifest.permission.READ_LOGS;
+import static android.Manifest.permission.READ_DROPBOX_DATA;
 
 import android.annotation.BytesLong;
 import android.annotation.CurrentTimeMillisLong;
@@ -81,9 +81,11 @@
 
     /**
      * Broadcast Action: This is broadcast when a new entry is added in the dropbox.
-     * You must hold the {@link android.Manifest.permission#READ_LOGS} permission
-     * in order to receive this broadcast. This broadcast can be rate limited for low priority
-     * entries
+     * For Android V+ (including V), you must hold the
+     * {@link android.Manifest.permission#READ_DROPBOX_DATA} permission in order
+     * to receive this broadcast. For Android version earlier than
+     * Android V, you must hold {@link android.Manifest.permission#READ_LOGS}.
+     * This broadcast can be rate limited for low priority entries
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
@@ -382,12 +384,16 @@
     /**
      * Gets the next entry from the drop box <em>after</em> the specified time.
      * You must always call {@link Entry#close()} on the return value!
+     * {@link android.Manifest.permission#READ_DROPBOX_DATA} permission is
+     * required for Android V or later.
+     * {@link android.Manifest.permission#READ_LOGS} permission is
+     * required for Android earlier than V.
      *
      * @param tag of entry to look for, null for all tags
      * @param msec time of the last entry seen
      * @return the next entry, or null if there are no more entries
      */
-    @RequiresPermission(allOf = { READ_LOGS, PACKAGE_USAGE_STATS })
+    @RequiresPermission(allOf = { READ_DROPBOX_DATA, PACKAGE_USAGE_STATS })
     public @Nullable Entry getNextEntry(String tag, long msec) {
         try {
             return mService.getNextEntryWithAttribution(tag, msec, mContext.getOpPackageName(),
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 d8e60c8..66ad12c 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -19,4 +19,21 @@
     name: "haptics_customization_ringtone_v2_enabled"
     description: "Enables the usage of the new RingtoneV2 class"
     bug: "241918098"
-}
\ No newline at end of file
+}
+
+flag {
+    namespace: "haptics"
+    name: "enable_vibration_serialization_apis"
+    description: "Enables the APIs for vibration serialization/deserialization."
+    bug: "245129509"
+}
+
+flag {
+    namespace: "haptics"
+    name: "haptic_feedback_vibration_oem_customization_enabled"
+    description: "Enables OEMs/devices to customize vibrations for haptic feedback"
+    # Make read only. This is because the flag is used only once, and this could happen before
+    # the read-write flag values propagate to the device.
+    is_fixed_read_only: true
+    bug: "291128479"
+}
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/provider/Settings.java b/core/java/android/provider/Settings.java
index b414ed4..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
@@ -11178,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.
          *
@@ -11607,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.
          *
@@ -12424,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.aidl b/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
deleted file mode 100644
index f8b843b..0000000
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.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 KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
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/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
index df93433..5d96f69 100644
--- a/core/java/android/service/credentials/BeginCreateCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
@@ -143,7 +143,7 @@
          *
          * <p> Note that as a provider service you will only be able to set a remote entry if :
          * - Provider service possesses the
-         * {@link Manifest.permission.PROVIDE_REMOTE_CREDENTIALS} permission.
+         * {@link Manifest.permission#PROVIDE_REMOTE_CREDENTIALS} permission.
          * - Provider service is configured as the provider that can provide remote entries.
          *
          * If the above conditions are not met, setting back {@link BeginCreateCredentialResponse}
diff --git a/core/java/android/service/credentials/BeginGetCredentialResponse.java b/core/java/android/service/credentials/BeginGetCredentialResponse.java
index 5ed06ac..ae6ca25 100644
--- a/core/java/android/service/credentials/BeginGetCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginGetCredentialResponse.java
@@ -160,7 +160,7 @@
          *
          * <p> Note that as a provider service you will only be able to set a remote entry if :
          * - Provider service possesses the
-         * {@link Manifest.permission.PROVIDE_REMOTE_CREDENTIALS} permission.
+         * {@link Manifest.permission#PROVIDE_REMOTE_CREDENTIALS} permission.
          * - Provider service is configured as the provider that can provide remote entries.
          *
          * If the above conditions are not met, setting back {@link BeginGetCredentialResponse}
diff --git a/core/java/android/service/credentials/CallingAppInfo.java b/core/java/android/service/credentials/CallingAppInfo.java
index e755581..c3524c5 100644
--- a/core/java/android/service/credentials/CallingAppInfo.java
+++ b/core/java/android/service/credentials/CallingAppInfo.java
@@ -103,7 +103,7 @@
      * of other applications.
      *
      * Android system makes sure that only applications that poses the permission
-     * {@link android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN} can set the origin on
+     * {@link android.Manifest.permission#CREDENTIAL_MANAGER_SET_ORIGIN} can set the origin on
      * the incoming {@link android.credentials.GetCredentialRequest} or
      * {@link android.credentials.CreateCredentialRequest}.
      */
diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
index 0aa6a23..514d722 100644
--- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java
+++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
@@ -45,8 +45,8 @@
 import android.util.Slog;
 import android.util.Xml;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -135,8 +135,8 @@
     }
 
     /**
-     * Constructs an information instance of the credential provider for testing purposes. Does
-     * not run any verifications and passes parameters as is.
+     * Constructs an information instance of the credential provider for testing purposes. Does not
+     * run any verifications and passes parameters as is.
      */
     @VisibleForTesting
     public static CredentialProviderInfo createForTests(
@@ -151,7 +151,6 @@
                 .setSystemProvider(isSystemProvider)
                 .addCapabilities(capabilities)
                 .build();
-
     }
 
     private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException {
@@ -267,15 +266,21 @@
                                     allAttributes,
                                     com.android.internal.R.styleable.CredentialProvider);
                     builder.setSettingsSubtitle(
-                            afsAttributes.getString(
+                            getAfsAttributeSafe(
+                                    afsAttributes,
                                     R.styleable.CredentialProvider_settingsSubtitle));
+                    builder.setSettingsActivity(
+                            getAfsAttributeSafe(
+                                    afsAttributes,
+                                    R.styleable.CredentialProvider_settingsActivity));
                 } catch (Exception e) {
-                    Slog.e(TAG, "Failed to get XML attr", e);
+                    Slog.w(TAG, "Failed to get XML attr for metadata", e);
                 } finally {
                     if (afsAttributes != null) {
                         afsAttributes.recycle();
                     }
                 }
+
                 builder.addCapabilities(parseXmlProviderOuterCapabilities(parser, resources));
             } else {
                 Slog.w(TAG, "Meta-data does not start with credential-provider-service tag");
@@ -287,6 +292,21 @@
         return builder;
     }
 
+    private static @Nullable String getAfsAttributeSafe(
+            @Nullable TypedArray afsAttributes, int resId) {
+        if (afsAttributes == null) {
+            return null;
+        }
+
+        try {
+            return afsAttributes.getString(resId);
+        } catch (Exception e) {
+            Slog.w(TAG, "Failed to get XML attr from afs attributes", e);
+        }
+
+        return null;
+    }
+
     private static List<String> parseXmlProviderOuterCapabilities(
             XmlPullParser parser, Resources resources) throws IOException, XmlPullParserException {
         final List<String> capabilities = new ArrayList<>();
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..c82a4ca 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;
@@ -25,17 +26,20 @@
 import android.system.OsConstants;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
 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 +68,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 +87,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 +112,34 @@
     }
 
     /**
-     * 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
+     */
+    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     public final boolean isFdNotNullAndClosed() {
         return mRankingMapFd != null && mRankingMapFd.getFd() == -1;
     }
@@ -145,9 +179,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 +228,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 +249,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/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index bb5dd7f..3ed13bb 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -536,7 +536,16 @@
     @MainThread
     public void setRecognitionListener(RecognitionListener listener) {
         checkIsCalledFromMainThread();
-        putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener));
+        if (mListener.mInternalListener == null) {
+            // This shortcut is needed because otherwise, if there's an error connecting, it never
+            // gets delivered. I.e., the onSuccess callback set up in connectToSystemService does
+            // not get called, MSG_CHANGE_LISTENER does not get executed, so the onError in the same
+            // place does not get forwarded anywhere.
+            // Thread-wise, this is safe as both this method and the handler are on the UI thread.
+            handleChangeListener(listener);
+        } else {
+            putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener));
+        }
     }
 
     /**
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/IWindow.aidl b/core/java/android/view/IWindow.aidl
index d554514..11180ae 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -54,6 +54,10 @@
      */
     void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
 
+    /**
+     * Please dispatch through WindowStateResizeItem instead of directly calling this method from
+     * the system server.
+     */
     void resized(in ClientWindowFrames frames, boolean reportDraw,
             in MergedConfiguration newMergedConfiguration, in InsetsState insetsState,
             boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
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/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/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 cf46bcc..b5648cc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1730,7 +1730,7 @@
                         attrs.getTitle().toString());
                 mAttachInfo.mThreadedRenderer = renderer;
                 renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
-                updateColorModeIfNeeded(attrs.getColorMode());
+                updateColorModeIfNeeded(attrs.getColorMode(), attrs.getDesiredHdrHeadroom());
                 updateRenderHdrSdrRatio();
                 updateForceDarkMode();
                 mAttachInfo.mHardwareAccelerated = true;
@@ -2232,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) {
@@ -3351,7 +3349,7 @@
                 }
                 final boolean alwaysConsumeSystemBarsChanged =
                         mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
-                updateColorModeIfNeeded(lp.getColorMode());
+                updateColorModeIfNeeded(lp.getColorMode(), lp.getDesiredHdrHeadroom());
                 surfaceCreated = !hadSurface && mSurface.isValid();
                 surfaceDestroyed = hadSurface && !mSurface.isValid();
 
@@ -3879,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()
@@ -3895,8 +3893,8 @@
                 mPendingTransitions.clear();
             }
             if (!performDraw(mActiveSurfaceSyncGroup)) {
-                handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mPendingTransaction,
-                        mLastPerformDrawSkippedReason);
+                handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
+                        mPendingTransaction, mLastPerformDrawSkippedReason);
             }
         }
 
@@ -4774,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();
@@ -4789,8 +4787,8 @@
         }
 
         if (!usingAsyncReport) {
-            handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction,
-                    "no async report");
+            handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null,
+                    pendingTransaction, "no async report");
         }
 
         if (mPerformContentCapture) {
@@ -4800,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) {
@@ -5320,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.
      */
@@ -5630,7 +5652,8 @@
         mUpdateHdrSdrRatioInfo = true;
     }
 
-    private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode) {
+    private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode,
+            float desiredRatio) {
         if (mAttachInfo.mThreadedRenderer == null) {
             return;
         }
@@ -5644,7 +5667,10 @@
                 && !getConfiguration().isScreenWideColorGamut()) {
             colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
         }
-        float desiredRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
+        float automaticRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
+        if (desiredRatio == 0 || desiredRatio > automaticRatio) {
+            desiredRatio = automaticRatio;
+        }
         if (desiredRatio != mDesiredHdrSdrRatio) {
             mDesiredHdrSdrRatio = desiredRatio;
             updateRenderHdrSdrRatio();
@@ -5942,6 +5968,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
@@ -6220,6 +6247,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;
@@ -8579,10 +8609,6 @@
             mLastLayoutFrame.set(frame);
         }
 
-        if (mOnBackInvokedDispatcher.isSystemGestureExclusionNeeded()) {
-            setRootSystemGestureExclusionRects(List.of(frame));
-        }
-
         final WindowConfiguration winConfig = getCompatWindowConfiguration();
         mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop()
                 ? winConfig.getMaxBounds()
@@ -9027,8 +9053,8 @@
             mAdded = false;
             AnimationHandler.removeRequestor(this);
         }
-        handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mPendingTransaction,
-                "shutting down VRI");
+        handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
+                mPendingTransaction, "shutting down VRI");
         WindowManagerGlobal.getInstance().doRemoveView(this);
     }
 
@@ -10521,6 +10547,8 @@
                 MergedConfiguration mergedConfiguration, InsetsState insetsState,
                 boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
                 boolean dragResizing) {
+            // Although this is a AIDL method, it will only be triggered in local process through
+            // either WindowStateResizeItem or WindowlessWindowManager.
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState,
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2f04b0c..87537fbc 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -24,6 +24,8 @@
 
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
+import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
 import android.annotation.NonNull;
@@ -1330,6 +1332,47 @@
     }
 
     /**
+     * <p>Sets the desired about of HDR headroom to be used when rendering as a ratio of
+     * targetHdrPeakBrightnessInNits / targetSdrWhitePointInNits. Only applies when
+     * {@link #setColorMode(int)} is {@link ActivityInfo#COLOR_MODE_HDR}</p>
+     *
+     * <p>By default the system will choose an amount of HDR headroom that is appropriate
+     * for the underlying device capabilities & bit-depth of the panel. However, for some types
+     * of content this can end up being more headroom than necessary or desired. An example
+     * would be a messaging app or gallery thumbnail view where some amount of HDR pop is desired
+     * without overly influencing the perceived brightness of the majority SDR content. This can
+     * also be used to animate in/out of an HDR range for smoother transitions.</p>
+     *
+     * <p>Note: The actual amount of HDR headroom that will be given is subject to a variety
+     * of factors such as ambient conditions, display capabilities, or bit-depth limitations.
+     * See {@link Display#getHdrSdrRatio()} for more information as well as how to query the
+     * current value.</p>
+     *
+     * @param desiredHeadroom The amount of HDR headroom that is desired. Must be >= 1.0 (no HDR)
+     *                        and <= 10,000.0. Passing 0.0 will reset to the default, automatically
+     *                        chosen value.
+     * @see #getDesiredHdrHeadroom()
+     * @see Display#getHdrSdrRatio()
+     */
+    @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_LIMITED_HDR)
+    public void setDesiredHdrHeadroom(
+            @FloatRange(from = 0.0f, to = 10000.0) float desiredHeadroom) {
+        final WindowManager.LayoutParams attrs = getAttributes();
+        attrs.setDesiredHdrHeadroom(desiredHeadroom);
+        dispatchWindowAttributesChanged(attrs);
+    }
+
+    /**
+     * Get the desired amount of HDR headroom as set by {@link #setDesiredHdrHeadroom(float)}
+     * @return The amount of HDR headroom set, or 0 for automatic/default behavior.
+     * @see #setDesiredHdrHeadroom(float)
+     */
+    @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_LIMITED_HDR)
+    public float getDesiredHdrHeadroom() {
+        return getAttributes().getDesiredHdrHeadroom();
+    }
+
+    /**
      * If {@code isPreferred} is true, this method requests that the connected display does minimal
      * post processing when this window is visible on the screen. Otherwise, it requests that the
      * display switches back to standard image processing.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2f4bea0..6c8f542 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -82,6 +82,8 @@
 
 import android.Manifest.permission;
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -4314,6 +4316,9 @@
         @ActivityInfo.ColorMode
         private int mColorMode = COLOR_MODE_DEFAULT;
 
+        /** @hide */
+        private float mDesiredHdrHeadroom = 0;
+
         /**
          * Carries the requests about {@link WindowInsetsController.Appearance} and
          * {@link WindowInsetsController.Behavior} to the system windows which can produce insets.
@@ -4716,6 +4721,39 @@
         }
 
         /**
+         * <p>Sets the desired about of HDR headroom to be used when rendering as a ratio of
+         * targetHdrPeakBrightnessInNits / targetSdrWhitePointInNits. Only applies when
+         * {@link #setColorMode(int)} is {@link ActivityInfo#COLOR_MODE_HDR}</p>
+         *
+         * @see Window#setDesiredHdrHeadroom(float)
+         * @param desiredHeadroom Desired amount of HDR headroom. Must be in the range of 1.0 (SDR)
+         *                        to 10,000.0, or 0.0 to reset to default.
+         */
+        @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_LIMITED_HDR)
+        public void setDesiredHdrHeadroom(
+                @FloatRange(from = 0.0f, to = 10000.0f) float desiredHeadroom) {
+            if (!Float.isFinite(desiredHeadroom)) {
+                throw new IllegalArgumentException("desiredHeadroom must be finite: "
+                        + desiredHeadroom);
+            }
+            if (desiredHeadroom != 0 && (desiredHeadroom < 1.0f || desiredHeadroom > 10000.0f)) {
+                throw new IllegalArgumentException(
+                        "desiredHeadroom must be 0.0 or in the range [1.0, 10000.0f], received: "
+                                + desiredHeadroom);
+            }
+            mDesiredHdrHeadroom = desiredHeadroom;
+        }
+
+        /**
+         * Get the desired amount of HDR headroom as set by {@link #setDesiredHdrHeadroom(float)}
+         * @return The amount of HDR headroom set, or 0 for automatic/default behavior.
+         */
+        @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_LIMITED_HDR)
+        public float getDesiredHdrHeadroom() {
+            return mDesiredHdrHeadroom;
+        }
+
+        /**
          * <p>
          * Blurs the screen behind the window. The effect is similar to that of {@link #dimAmount},
          * but instead of dimmed, the content behind the window will be blurred (or combined with
@@ -4865,6 +4903,7 @@
             checkNonRecursiveParams();
             out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
             out.writeInt(mDisplayFlags);
+            out.writeFloat(mDesiredHdrHeadroom);
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -4936,6 +4975,7 @@
             forciblyShownTypes = in.readInt();
             paramsForRotation = in.createTypedArray(LayoutParams.CREATOR);
             mDisplayFlags = in.readInt();
+            mDesiredHdrHeadroom = in.readFloat();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -5196,6 +5236,11 @@
                 changes |= COLOR_MODE_CHANGED;
             }
 
+            if (mDesiredHdrHeadroom != o.mDesiredHdrHeadroom) {
+                mDesiredHdrHeadroom = o.mDesiredHdrHeadroom;
+                changes |= COLOR_MODE_CHANGED;
+            }
+
             if (preferMinimalPostProcessing != o.preferMinimalPostProcessing) {
                 preferMinimalPostProcessing = o.preferMinimalPostProcessing;
                 changes |= MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED;
@@ -5423,6 +5468,9 @@
             if (mColorMode != COLOR_MODE_DEFAULT) {
                 sb.append(" colorMode=").append(ActivityInfo.colorModeToString(mColorMode));
             }
+            if (mDesiredHdrHeadroom != 0) {
+                sb.append(" desiredHdrHeadroom=").append(mDesiredHdrHeadroom);
+            }
             if (preferMinimalPostProcessing) {
                 sb.append(" preferMinimalPostProcessing=");
                 sb.append(preferMinimalPostProcessing);
@@ -5821,6 +5869,7 @@
      *
      * @hide
      */
+    @FlaggedApi("REPLACE_CONTENT_WITH_MIRROR")
     @TestApi
     @RequiresPermission(permission.ACCESS_SURFACE_FLINGER)
     default boolean replaceContentOnDisplayWithMirror(int displayId, @NonNull Window window) {
@@ -5836,6 +5885,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 8fe9b7b..7c3b6ae 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -584,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
index e31ad82..85dadd4 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -5,4 +5,11 @@
     name: "force_invert_color"
     description: "Enable force force-dark for smart inversion and dark theme everywhere"
     bug: "282821643"
-}
\ No newline at end of file
+}
+
+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/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 2c7d326..42b3e38 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -60,7 +60,9 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -377,6 +379,30 @@
     public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE =
             "content_protection_buffer_size";
 
+    /**
+     * Sets the config for content protection required groups.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG =
+            "content_protection_required_groups_config";
+
+    /**
+     * Sets the config for content protection optional groups.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG =
+            "content_protection_optional_groups_config";
+
+    /**
+     * Sets the threshold for content protection optional groups.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD =
+            "content_protection_optional_groups_threshold";
+
     /** @hide */
     @TestApi
     public static final int LOGGING_LEVEL_OFF = 0;
@@ -417,6 +443,18 @@
     public static final int DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE = 5000;
     /** @hide */
     public static final int DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE = 150;
+    /** @hide */
+    public static final List<List<String>> DEFAULT_CONTENT_PROTECTION_REQUIRED_GROUPS =
+            Collections.emptyList();
+    /** @hide */
+    public static final String DEFAULT_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG = "";
+    /** @hide */
+    public static final List<List<String>> DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS =
+            Collections.emptyList();
+    /** @hide */
+    public static final String DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG = "";
+    /** @hide */
+    public static final int DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD = 0;
 
     private final Object mLock = new Object();
 
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/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/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
index b2c977b..07ac292 100644
--- a/core/java/android/window/SystemPerformanceHinter.java
+++ b/core/java/android/window/SystemPerformanceHinter.java
@@ -17,6 +17,8 @@
 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;
 
@@ -29,8 +31,6 @@
 import android.util.Log;
 import android.view.SurfaceControl;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Random;
@@ -148,7 +148,6 @@
      * Constructor for the hinter.
      * @hide
      */
-    @VisibleForTesting
     public SystemPerformanceHinter(@NonNull Context context,
             @Nullable DisplayRootProvider displayRootProvider,
             @Nullable Supplier<SurfaceControl.Transaction> transactionSupplier) {
@@ -208,11 +207,14 @@
         boolean transactionChanged = false;
         // Per-display flags
         if (nowEnabled(oldPerDisplayFlags, newPerDisplayFlags, HINT_SF_FRAME_RATE)) {
-            mTransaction.setFrameRateSelectionStrategy(
-                    mDisplayRootProvider.getRootForDisplay(session.displayId),
+            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.reason, session.traceCookie);
+            Trace.beginAsyncSection("PerfHint-framerate-" + session.displayId + "-"
+                    + session.reason, session.traceCookie);
         }
 
         // Global flags
@@ -226,7 +228,7 @@
             Trace.beginAsyncSection("PerfHint-adpf-" + session.reason, session.traceCookie);
         }
         if (transactionChanged) {
-            mTransaction.apply();
+            mTransaction.applyAsyncUnsafe();
         }
     }
 
@@ -245,25 +247,28 @@
         boolean transactionChanged = false;
         // Per-display flags
         if (nowDisabled(oldPerDisplayFlags, newPerDisplayFlags, HINT_SF_FRAME_RATE)) {
-            mTransaction.setFrameRateSelectionStrategy(
-                    mDisplayRootProvider.getRootForDisplay(session.displayId),
+            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.reason, session.traceCookie);
+            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);
+            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.apply();
+            mTransaction.applyAsyncUnsafe();
         }
     }
 
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
index 1b98806..ccbf4a9 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -9,3 +9,11 @@
     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/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index ec5d4ff..24dc6db 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -22,3 +22,10 @@
     description: "Whether the TaskFragment system organizer feature is enabled"
     bug: "284050041"
 }
+
+flag {
+    namespace: "windowing_sdk"
+    name: "window_state_resize_item_flag"
+    description: "Whether to dispatch window resize through ClientTransaction is enabled"
+    bug: "301870955"
+}
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/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/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..e120f82 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" />
@@ -2107,12 +2108,12 @@
         android:protectionLevel="signature" />
 
     <!-- Allows direct access to the <RemoteAuth>Service interfaces.
-         @hide @TestApi @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES) -->
+         @hide -->
     <permission android:name="android.permission.MANAGE_REMOTE_AUTH"
                 android:protectionLevel="signature" />
 
     <!-- Allows direct access to the <RemoteAuth>Service authentication methods.
-         @hide @TestApi @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES) -->
+         @hide -->
     <permission android:name="android.permission.USE_REMOTE_AUTH"
                 android:protectionLevel="signature" />
 
@@ -4564,6 +4565,12 @@
     <permission android:name="android.permission.SET_DEBUG_APP"
         android:protectionLevel="signature|privileged|development" />
 
+    <!-- Allows an application to access the data in Dropbox.
+    <p>Not for use by third-party applications.
+    @hide -->
+    <permission android:name="android.permission.READ_DROPBOX_DATA"
+        android:protectionLevel="signature|privileged|development" />
+
     <!-- Allows an application to set the maximum number of (not needed)
          application processes that can be running.
          <p>Not for use by third-party applications. -->
@@ -7232,6 +7239,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/drawable-nodpi/usb_cable_unknown_issue.xml b/core/res/res/drawable-nodpi/usb_cable_unknown_issue.xml
new file mode 100644
index 0000000..dddad81
--- /dev/null
+++ b/core/res/res/drawable-nodpi/usb_cable_unknown_issue.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="20"
+        android:viewportHeight="20">
+    <path
+        android:pathData="M15.333,5.333V4.667C15.333,4.3 15.033,4 14.667,4L13.333,4C12.967,4 12.667,4.3 12.667,4.667V5.333H12V8C12,8.367 12.3,8.667 12.667,8.667H13.333L13.333,13.333C13.333,14.067 12.733,14.667 12,14.667C11.267,14.667 10.667,14.067 10.667,13.333L10.667,11.333V6.667C10.667,5.193 9.473,4 8,4C6.527,4 5.333,5.193 5.333,6.667L5.333,11.333H4.667C4.3,11.333 4,11.633 4,12L4,14.667H4.667V15.333C4.667,15.7 4.967,16 5.333,16H6.667C7.033,16 7.333,15.7 7.333,15.333V14.667H8L8,12C8,11.633 7.7,11.333 7.333,11.333H6.667L6.667,6.667C6.667,5.933 7.267,5.333 8,5.333C8.733,5.333 9.333,5.933 9.333,6.667V11.333L9.333,13.333C9.333,14.807 10.527,16 12,16C13.473,16 14.667,14.807 14.667,13.333L14.667,8.667H15.333C15.7,8.667 16,8.367 16,8V5.333H15.333Z"
+        android:fillColor="#FFFFFFFF"
+        android:fillType="evenOdd"/>
+</vector>
+
+
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/attrs.xml b/core/res/res/values/attrs.xml
index e54347f..04fd70a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -10118,6 +10118,9 @@
              screen that can be used to provide more information about a provider. For
              longer strings it will be truncated. -->
         <attr name="settingsSubtitle" format="string" />
+        <!-- Fully qualified class name of an activity that allows the user to modify
+             the settings for this service. -->
+        <attr name="settingsActivity" />
     </declare-styleable>
 
     <!-- A list of capabilities that indicates to the OS what kinds of credentials
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4360c5a..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)
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fac6aac..a2a4e34f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -826,6 +826,9 @@
          security policy. [CHAR_LIMIT=NONE]-->
     <string name="notification_channel_accessibility_security_policy">Accessibility usage</string>
 
+    <!-- Text shown when viewing channel settings for notifications related to displays -->
+    <string name="notification_channel_display">Display</string>
+
     <!-- Label for foreground service notification when one app is running.
     [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6826789589341671842] -->
     <string name="foreground_service_app_in_background"><xliff:g id="app_name">%1$s</xliff:g> is
@@ -6290,6 +6293,16 @@
     <!-- Toast message that is shown when the user mutes the microphone from the keyboard. [CHAR LIMIT=TOAST] -->
     <string name="mic_access_off_toast">Microphone is blocked</string>
 
+    <!-- Title of connected display unavailable notifications. [CHAR LIMIT=NONE] -->
+    <string name="connected_display_unavailable_notification_title">Can\'t mirror to display</string>
+    <!-- Content of connected display unavailable notification. [CHAR LIMIT=NONE] -->
+    <string name="connected_display_unavailable_notification_content">Use a different cable and try again</string>
+
+    <!-- Title of cable don't support displays notifications. [CHAR LIMIT=NONE] -->
+    <string name="connected_display_cable_dont_support_displays_notification_title">Cable may not support displays</string>
+    <!-- Content of cable don't support displays notification. [CHAR LIMIT=NONE] -->
+    <string name="connected_display_cable_dont_support_displays_notification_content">Your USB-C cable may not connect to displays properly</string>
+
     <!-- Name of concurrent display notifications. [CHAR LIMIT=NONE] -->
     <string name="concurrent_display_notification_name">Dual screen</string>
     <!-- Title of concurrent display active notification. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7f30695..c1ecb05 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" />
@@ -1996,6 +1997,7 @@
   <java-symbol type="drawable" name="stat_sys_throttled" />
   <java-symbol type="drawable" name="vpn_connected" />
   <java-symbol type="drawable" name="vpn_disconnected" />
+  <java-symbol type="drawable" name="usb_cable_unknown_issue" />
   <java-symbol type="id" name="ask_checkbox" />
   <java-symbol type="id" name="compat_checkbox" />
   <java-symbol type="id" name="original_app_icon" />
@@ -3485,6 +3487,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.
@@ -3810,6 +3814,7 @@
   <java-symbol type="string" name="notification_channel_do_not_disturb" />
   <java-symbol type="string" name="notification_channel_accessibility_magnification" />
   <java-symbol type="string" name="notification_channel_accessibility_security_policy" />
+  <java-symbol type="string" name="notification_channel_display" />
   <java-symbol type="string" name="config_defaultAutofillService" />
   <java-symbol type="string" name="config_defaultFieldClassificationService" />
   <java-symbol type="string" name="config_defaultOnDeviceSpeechRecognitionService" />
@@ -5063,6 +5068,10 @@
   <java-symbol type="array" name="device_state_notification_thermal_contents"/>
   <java-symbol type="array" name="device_state_notification_power_save_titles"/>
   <java-symbol type="array" name="device_state_notification_power_save_contents"/>
+  <java-symbol type="string" name="connected_display_unavailable_notification_title"/>
+  <java-symbol type="string" name="connected_display_unavailable_notification_content"/>
+  <java-symbol type="string" name="connected_display_cable_dont_support_displays_notification_title"/>
+  <java-symbol type="string" name="connected_display_cable_dont_support_displays_notification_content"/>
   <java-symbol type="string" name="concurrent_display_notification_name"/>
   <java-symbol type="string" name="concurrent_display_notification_active_title"/>
   <java-symbol type="string" name="concurrent_display_notification_active_content"/>
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 824f591..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
@@ -610,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();
 
@@ -621,9 +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);
-        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(any());
         doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
 
         mTunerSessions[0].cancel();
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 3b9d7ba..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
@@ -540,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();
 
@@ -551,8 +549,6 @@
     @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();
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 81dab08..2993a0e 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -64,6 +64,7 @@
         "servicestests-utils",
         "device-time-shell-utils",
         "testables",
+        "com.android.text.flags-aconfig-java",
     ],
 
     libs: [
diff --git a/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java
new file mode 100644
index 0000000..c00eb91
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java
@@ -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 android.app.servertransaction;
+
+import static org.mockito.Mockito.verify;
+
+import android.app.ClientTransactionHandler;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.util.MergedConfiguration;
+import android.view.IWindow;
+import android.view.InsetsState;
+import android.window.ClientWindowFrames;
+
+import androidx.test.filters.SmallTest;
+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;
+
+/**
+ * Tests for {@link WindowStateResizeItem}.
+ *
+ * Build/Install/Run:
+ *  atest FrameworksCoreTests:WindowStateResizeItemTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class WindowStateResizeItemTest {
+
+    @Mock
+    private ClientTransactionHandler mHandler;
+    @Mock
+    private PendingTransactionActions mPendingActions;
+    @Mock
+    private IWindow mWindow;
+    @Mock
+    private ClientWindowFrames mFrames;
+    @Mock
+    private MergedConfiguration mConfiguration;
+    @Mock
+    private InsetsState mInsetsState;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testExecute() throws RemoteException {
+        final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames,
+                true /* reportDraw */, mConfiguration, mInsetsState, true /* forceLayout */,
+                true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */,
+                true /* dragResizing */);
+        item.execute(mHandler, mPendingActions);
+
+        verify(mWindow).resized(mFrames,
+                true /* reportDraw */, mConfiguration, mInsetsState, true /* forceLayout */,
+                true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */,
+                true /* dragResizing */);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java b/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java
index f8348d2..eefa6e4 100644
--- a/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java
+++ b/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java
@@ -32,6 +32,8 @@
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.List;
+
 /**
  * Unit test for {@link ContentCaptureOptions}.
  *
@@ -44,6 +46,9 @@
     private static final ComponentName CONTEXT_COMPONENT = new ComponentName("marco", "polo");
     private static final ComponentName COMPONENT1 = new ComponentName("comp", "one");
     private static final ComponentName COMPONENT2 = new ComponentName("two", "comp");
+    private static final List<List<String>> CONTENT_PROTECTION_REQUIRED_GROUPS =
+            List.of(List.of("first"), List.of("second", "third"), List.of());
+    private static final List<List<String>> CONTENT_PROTECTION_OPTIONAL_GROUPS = List.of();
     private static final ContentCaptureOptions CONTENT_CAPTURE_OPTIONS =
             new ContentCaptureOptions(
                     /* loggingLevel= */ 1000,
@@ -55,7 +60,10 @@
                     /* enableReceiver= */ false,
                     new ContentCaptureOptions.ContentProtectionOptions(
                             /* enableReceiver= */ true,
-                            /* bufferSize= */ 2001),
+                            /* bufferSize= */ 2001,
+                            CONTENT_PROTECTION_REQUIRED_GROUPS,
+                            CONTENT_PROTECTION_OPTIONAL_GROUPS,
+                            /* optionalGroupsThreshold= */ 2002),
                     /* whitelistedComponents= */ toSet(COMPONENT1, COMPONENT2));
 
     @Mock private Context mContext;
@@ -134,6 +142,19 @@
                         .append(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.enableReceiver)
                         .append(", bufferSize=")
                         .append(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.bufferSize)
+                        .append(", requiredGroupsSize=")
+                        .append(
+                                CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.requiredGroups
+                                        .size())
+                        .append(", optionalGroupsSize=")
+                        .append(
+                                CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.optionalGroups
+                                        .size())
+                        .append(", optionalGroupsThreshold=")
+                        .append(
+                                CONTENT_CAPTURE_OPTIONS
+                                        .contentProtectionOptions
+                                        .optionalGroupsThreshold)
                         .append("], whitelisted=")
                         .append(CONTENT_CAPTURE_OPTIONS.whitelistedComponents)
                         .append(']')
@@ -166,6 +187,15 @@
                 .isEqualTo(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.enableReceiver);
         assertThat(actual.contentProtectionOptions.bufferSize)
                 .isEqualTo(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.bufferSize);
+        assertThat(actual.contentProtectionOptions.requiredGroups)
+                .containsExactlyElementsIn(
+                        CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.requiredGroups);
+        assertThat(actual.contentProtectionOptions.optionalGroups)
+                .containsExactlyElementsIn(
+                        CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.optionalGroups);
+        assertThat(actual.contentProtectionOptions.optionalGroupsThreshold)
+                .isEqualTo(
+                        CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.optionalGroupsThreshold);
         assertThat(actual.whitelistedComponents)
                 .containsExactlyElementsIn(CONTENT_CAPTURE_OPTIONS.whitelistedComponents);
     }
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/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
index 101f7c2..5c411d5 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
@@ -31,6 +31,8 @@
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.Collections;
+
 /**
  * Unit test for {@link ContentCaptureManager}.
  *
@@ -69,7 +71,11 @@
         ContentCaptureOptions options =
                 createOptions(
                         new ContentCaptureOptions.ContentProtectionOptions(
-                                /* enableReceiver= */ false, BUFFER_SIZE));
+                                /* enableReceiver= */ false,
+                                BUFFER_SIZE,
+                                /* requiredGroups= */ Collections.emptyList(),
+                                /* optionalGroups= */ Collections.emptyList(),
+                                /* optionalGroupsThreshold= */ 0));
 
         ContentCaptureManager manager =
                 new ContentCaptureManager(mMockContext, mMockContentCaptureManager, options);
@@ -82,7 +88,11 @@
         ContentCaptureOptions options =
                 createOptions(
                         new ContentCaptureOptions.ContentProtectionOptions(
-                                /* enableReceiver= */ true, /* bufferSize= */ 0));
+                                /* enableReceiver= */ true,
+                                /* bufferSize= */ 0,
+                                /* requiredGroups= */ Collections.emptyList(),
+                                /* optionalGroups= */ Collections.emptyList(),
+                                /* optionalGroupsThreshold= */ 0));
 
         ContentCaptureManager manager =
                 new ContentCaptureManager(mMockContext, mMockContentCaptureManager, options);
@@ -95,7 +105,11 @@
         ContentCaptureOptions options =
                 createOptions(
                         new ContentCaptureOptions.ContentProtectionOptions(
-                                /* enableReceiver= */ true, BUFFER_SIZE));
+                                /* enableReceiver= */ true,
+                                BUFFER_SIZE,
+                                /* requiredGroups= */ Collections.emptyList(),
+                                /* optionalGroups= */ Collections.emptyList(),
+                                /* optionalGroupsThreshold= */ 0));
 
         ContentCaptureManager manager =
                 new ContentCaptureManager(mMockContext, mMockContentCaptureManager, options);
diff --git a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
index 3373b8b..e76d266 100644
--- a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
@@ -47,6 +47,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -112,7 +113,11 @@
                 createOptions(
                         /* enableContentCaptureReceiver= */ true,
                         new ContentCaptureOptions.ContentProtectionOptions(
-                                /* enableReceiver= */ true, -BUFFER_SIZE));
+                                /* enableReceiver= */ true,
+                                -BUFFER_SIZE,
+                                /* requiredGroups= */ Collections.emptyList(),
+                                /* optionalGroups= */ Collections.emptyList(),
+                                /* optionalGroupsThreshold= */ 0));
         MainContentCaptureSession session = createSession(options);
         session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
 
@@ -313,7 +318,11 @@
         return createOptions(
                 enableContentCaptureReceiver,
                 new ContentCaptureOptions.ContentProtectionOptions(
-                        enableContentProtectionReceiver, BUFFER_SIZE));
+                        enableContentProtectionReceiver,
+                        BUFFER_SIZE,
+                        /* requiredGroups= */ Collections.emptyList(),
+                        /* optionalGroups= */ Collections.emptyList(),
+                        /* optionalGroupsThreshold= */ 0));
     }
 
     private ContentCaptureManager createManager(ContentCaptureOptions options) {
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
index 25f5819..263e563 100644
--- a/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java
+++ b/core/tests/coretests/src/android/window/SystemPerformanceHinterTests.java
@@ -18,6 +18,8 @@
 
 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;
@@ -150,7 +152,10 @@
         verify(mTransaction).setFrameRateSelectionStrategy(
                 eq(mDefaultDisplayRoot),
                 eq(FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN));
-        verify(mTransaction).apply();
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_HIGH));
+        verify(mTransaction).applyAsyncUnsafe();
     }
 
     @Test
@@ -164,7 +169,10 @@
         verify(mTransaction).setFrameRateSelectionStrategy(
                 eq(mDefaultDisplayRoot),
                 eq(FRAME_RATE_SELECTION_STRATEGY_SELF));
-        verify(mTransaction).apply();
+        verify(mTransaction).setFrameRateCategory(
+                eq(mDefaultDisplayRoot),
+                eq(FRAME_RATE_CATEGORY_DEFAULT));
+        verify(mTransaction).applyAsyncUnsafe();
     }
 
     @Test
@@ -177,7 +185,7 @@
 
         // Verify we call SF
         verify(mTransaction).setEarlyWakeupStart();
-        verify(mTransaction).apply();
+        verify(mTransaction).applyAsyncUnsafe();
     }
 
     @Test
@@ -189,7 +197,7 @@
 
         // Verify we call SF
         verify(mTransaction).setEarlyWakeupEnd();
-        verify(mTransaction).apply();
+        verify(mTransaction).applyAsyncUnsafe();
     }
 
     @Test
@@ -231,8 +239,11 @@
         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).apply();
+        verify(mTransaction).applyAsyncUnsafe();
         verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP));
     }
 
@@ -248,8 +259,11 @@
         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).apply();
+        verify(mTransaction).applyAsyncUnsafe();
         verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
     }
 
@@ -265,8 +279,11 @@
             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).apply();
+            verify(mTransaction).applyAsyncUnsafe();
             verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
         }
     }
@@ -280,8 +297,11 @@
         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).apply();
+        verify(mTransaction).applyAsyncUnsafe();
         verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP));
         reset(mTransaction);
         reset(mAdpfSession);
@@ -290,15 +310,17 @@
                 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()).apply();
+        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()).apply();
+        verify(mTransaction, never()).applyAsyncUnsafe();
         verify(mAdpfSession, never()).sendHint(anyInt());
 
         session1.close();
@@ -306,8 +328,11 @@
         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).apply();
+        verify(mTransaction).applyAsyncUnsafe();
         verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
     }
 
@@ -321,8 +346,11 @@
         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).apply();
+        verify(mTransaction).applyAsyncUnsafe();
         verify(mAdpfSession).sendHint(eq(CPU_LOAD_UP));
         reset(mTransaction);
         reset(mAdpfSession);
@@ -333,8 +361,11 @@
         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).apply();
+        verify(mTransaction).applyAsyncUnsafe();
         verify(mAdpfSession, never()).sendHint(anyInt());
         reset(mTransaction);
         reset(mAdpfSession);
@@ -345,11 +376,17 @@
         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).apply();
+        verify(mTransaction).applyAsyncUnsafe();
         verify(mAdpfSession, never()).sendHint(anyInt());
         reset(mTransaction);
         reset(mAdpfSession);
@@ -362,8 +399,11 @@
         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).apply();
+        verify(mTransaction).applyAsyncUnsafe();
         verify(mAdpfSession).sendHint(eq(CPU_LOAD_RESET));
     }
 
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/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/packages/SystemUI/ktfmt_includes.txt b/ktfmt_includes.txt
similarity index 99%
rename from packages/SystemUI/ktfmt_includes.txt
rename to ktfmt_includes.txt
index d3254b7..e4bf4c2 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/ktfmt_includes.txt
@@ -1,3 +1,4 @@
++services/permission
 +packages/SystemUI
 -packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
 -packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
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/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 7a309f5..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>
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 38550b4..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;
@@ -38,6 +39,7 @@
 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;
@@ -69,10 +71,17 @@
 
     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());
         }
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/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/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 e6d3abc..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
@@ -110,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
@@ -658,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 5dfba5e..14a040a 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
@@ -203,6 +203,7 @@
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
             ShellController shellController,
+            DisplayInsetsController displayInsetsController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
             Optional<DesktopTasksController> desktopTasksController,
@@ -218,6 +219,7 @@
                     taskOrganizer,
                     displayController,
                     shellController,
+                    displayInsetsController,
                     syncQueue,
                     transitions,
                     desktopTasksController,
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/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 e828eed..451e618 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
@@ -50,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;
@@ -344,6 +345,8 @@
                     // Keyguard handler cannot handle it, process through original mixed
                     mActiveTransitions.remove(keyguardMixed);
                 }
+            } else if (mPipHandler != null) {
+                mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction);
             }
         }
 
@@ -511,8 +514,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);
 
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/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 82fc0f4..aff35a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -231,4 +231,9 @@
     int getCaptionHeightId(@WindowingMode int windowingMode) {
         return R.dimen.freeform_decor_caption_height;
     }
+
+    @Override
+    int getCaptionViewId() {
+        return R.id.caption;
+    }
 }
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 bf99ab3..ca91d58 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
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.WindowInsets.Type.statusBars;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -50,6 +51,8 @@
 import android.view.InputEvent;
 import android.view.InputEventReceiver;
 import android.view.InputMonitor;
+import android.view.InsetsSource;
+import android.view.InsetsState;
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
@@ -67,6 +70,7 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
@@ -131,6 +135,8 @@
     private final DesktopModeKeyguardChangeListener mDesktopModeKeyguardChangeListener =
             new DesktopModeKeyguardChangeListener();
     private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
+    private final DisplayInsetsController mDisplayInsetsController;
+    private boolean mInImmersiveMode;
 
     public DesktopModeWindowDecorViewModel(
             Context context,
@@ -141,6 +147,7 @@
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
             ShellController shellController,
+            DisplayInsetsController displayInsetsController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
             Optional<DesktopTasksController> desktopTasksController,
@@ -156,6 +163,7 @@
                 taskOrganizer,
                 displayController,
                 shellController,
+                displayInsetsController,
                 syncQueue,
                 transitions,
                 desktopTasksController,
@@ -176,6 +184,7 @@
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
             ShellController shellController,
+            DisplayInsetsController displayInsetsController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
             Optional<DesktopTasksController> desktopTasksController,
@@ -191,6 +200,7 @@
         mTaskOrganizer = taskOrganizer;
         mShellController = shellController;
         mDisplayController = displayController;
+        mDisplayInsetsController = displayInsetsController;
         mSyncQueue = syncQueue;
         mTransitions = transitions;
         mDesktopTasksController = desktopTasksController;
@@ -213,6 +223,8 @@
             }
         });
         mShellCommandHandler.addDumpCallback(this::dump, this);
+        mDisplayInsetsController.addInsetsChangedListener(mContext.getDisplayId(),
+                new DesktopModeOnInsetsChangedListener());
     }
 
     @Override
@@ -655,9 +667,9 @@
     private void handleReceivedMotionEvent(MotionEvent ev, InputMonitor inputMonitor) {
         final DesktopModeWindowDecoration relevantDecor = getRelevantWindowDecor(ev);
         if (DesktopModeStatus.isEnabled()) {
-            if (relevantDecor == null
+            if (!mInImmersiveMode && (relevantDecor == null
                     || relevantDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM
-                    || mTransitionDragActive) {
+                    || mTransitionDragActive)) {
                 handleCaptionThroughStatusBar(ev, relevantDecor);
             }
         }
@@ -1051,6 +1063,35 @@
             return mIsKeyguardVisible && mIsKeyguardOccluded;
         }
     }
+
+    @VisibleForTesting
+    class DesktopModeOnInsetsChangedListener implements
+            DisplayInsetsController.OnInsetsChangedListener {
+        @Override
+        public void insetsChanged(InsetsState insetsState) {
+            for (int i = 0; i < insetsState.sourceSize(); i++) {
+                final InsetsSource source = insetsState.sourceAt(i);
+                if (source.getType() != statusBars()) {
+                    continue;
+                }
+
+                final DesktopModeWindowDecoration decor = getFocusedDecor();
+                if (decor == null) {
+                    return;
+                }
+                // If status bar inset is visible, top task is not in immersive mode
+                final boolean inImmersiveMode = !source.isVisible();
+                // Calls WindowDecoration#relayout if decoration visibility needs to be updated
+                if (inImmersiveMode != mInImmersiveMode) {
+                    decor.relayout(decor.mTaskInfo);
+                    mInImmersiveMode = inImmersiveMode;
+                }
+
+                return;
+            }
+        }
+    }
+
 }
 
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 380b59e..248e837 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -638,6 +638,11 @@
         return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId(windowingMode));
     }
 
+    @Override
+    int getCaptionViewId() {
+        return R.id.desktop_mode_caption;
+    }
+
     /**
      * Add transition to mTransitionsPausingRelayout
      */
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 6062e34..0548a8e 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
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowInsets.Type.statusBars;
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.WindowConfiguration.WindowingMode;
@@ -30,6 +31,8 @@
 import android.graphics.Rect;
 import android.os.Binder;
 import android.view.Display;
+import android.view.InsetsSource;
+import android.view.InsetsState;
 import android.view.LayoutInflater;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost;
@@ -44,6 +47,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;
 
@@ -118,6 +122,7 @@
     private WindowlessWindowManager mCaptionWindowManager;
     private SurfaceControlViewHost mViewHost;
     private Configuration mWindowDecorConfig;
+    private boolean mIsCaptionVisible;
 
     private final Binder mOwner = new Binder();
     private final Rect mCaptionInsetsRect = new Rect();
@@ -224,6 +229,8 @@
                     .inflate(params.mLayoutResId, null);
         }
 
+        updateCaptionVisibility(outResult.mRootView, mTaskInfo.displayId);
+
         final Resources resources = mDecorWindowContext.getResources();
         final Configuration taskConfig = mTaskInfo.getConfiguration();
         final Rect taskBounds = taskConfig.windowConfiguration.getBounds();
@@ -271,22 +278,26 @@
 
             // Caption insets
             mCaptionInsetsRect.set(taskBounds);
-            mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight + params.mCaptionY;
-            wct.addInsetsSource(mTaskInfo.token,
-                    mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect);
-            wct.addInsetsSource(mTaskInfo.token,
-                    mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(),
-                    mCaptionInsetsRect);
+            if (mIsCaptionVisible) {
+                mCaptionInsetsRect.bottom =
+                        mCaptionInsetsRect.top + captionHeight + params.mCaptionY;
+                wct.addInsetsSource(mTaskInfo.token,
+                        mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect);
+                wct.addInsetsSource(mTaskInfo.token,
+                        mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(),
+                        mCaptionInsetsRect);
+            } else {
+                wct.removeInsetsSource(mTaskInfo.token, mOwner, 0 /* index */,
+                        WindowInsets.Type.captionBar());
+                wct.removeInsetsSource(mTaskInfo.token, mOwner, 0 /* index */,
+                        WindowInsets.Type.mandatorySystemGestures());
+            }
         } else {
             startT.hide(mCaptionContainerSurface);
         }
 
         // 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 +313,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) {
@@ -342,10 +362,41 @@
         }
     }
 
+    /**
+     * Checks if task has entered/exited immersive mode and requires a change in caption visibility.
+     */
+    private void updateCaptionVisibility(View rootView, int displayId) {
+        final InsetsState insetsState = mDisplayController.getInsetsState(displayId);
+        for (int i = 0; i < insetsState.sourceSize(); i++) {
+            final InsetsSource source = insetsState.sourceAt(i);
+            if (source.getType() != statusBars()) {
+                continue;
+            }
+
+            mIsCaptionVisible = source.isVisible();
+            setCaptionVisibility(rootView, mIsCaptionVisible);
+
+            return;
+        }
+    }
+
+    private void setCaptionVisibility(View rootView, boolean visible) {
+        if (rootView == null) {
+            return;
+        }
+        final int v = visible ? View.VISIBLE : View.GONE;
+        final View captionView = rootView.findViewById(getCaptionViewId());
+        captionView.setVisibility(v);
+    }
+
     int getCaptionHeightId(@WindowingMode int windowingMode) {
         return Resources.ID_NULL;
     }
 
+    int getCaptionViewId() {
+        return Resources.ID_NULL;
+    }
+
     /**
      * Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or
      * registers {@link #mOnDisplaysChangedListener} if it doesn't.
@@ -460,7 +511,8 @@
      */
     public void addCaptionInset(WindowContainerTransaction wct) {
         final int captionHeightId = getCaptionHeightId(mTaskInfo.getWindowingMode());
-        if (!ViewRootImpl.CAPTION_ON_SHELL || captionHeightId == Resources.ID_NULL) {
+        if (!ViewRootImpl.CAPTION_ON_SHELL || captionHeightId == Resources.ID_NULL
+                || !mIsCaptionVisible) {
             return;
         }
 
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/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 d09a90c..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",
@@ -49,6 +50,7 @@
         "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/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/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index 8eaf5a0..57aa47e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -33,8 +33,12 @@
 import android.view.Display.DEFAULT_DISPLAY
 import android.view.InputChannel
 import android.view.InputMonitor
+import android.view.InsetsSource
+import android.view.InsetsState
 import android.view.SurfaceControl
 import android.view.SurfaceView
+import android.view.WindowInsets.Type.navigationBars
+import android.view.WindowInsets.Type.statusBars
 import androidx.core.content.getSystemService
 import androidx.test.filters.SmallTest
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
@@ -42,6 +46,7 @@
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.TestRunningTaskInfoBuilder
 import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayInsetsController
 import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.common.SyncTransactionQueue
@@ -53,10 +58,12 @@
 import com.android.wm.shell.sysui.ShellController
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
@@ -68,6 +75,7 @@
 import java.util.Optional
 import java.util.function.Supplier
 
+
 /** Tests of [DesktopModeWindowDecorViewModel]  */
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -80,6 +88,7 @@
     @Mock private lateinit var mockTaskOrganizer: ShellTaskOrganizer
     @Mock private lateinit var mockDisplayController: DisplayController
     @Mock private lateinit var mockDisplayLayout: DisplayLayout
+    @Mock private lateinit var displayInsetsController: DisplayInsetsController
     @Mock private lateinit var mockSyncQueue: SyncTransactionQueue
     @Mock private lateinit var mockDesktopTasksController: DesktopTasksController
     @Mock private lateinit var mockInputMonitor: InputMonitor
@@ -97,6 +106,7 @@
     }
 
     private lateinit var shellInit: ShellInit
+    private lateinit var desktopModeOnInsetsChangedListener: DesktopModeOnInsetsChangedListener
     private lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel
 
     @Before
@@ -111,6 +121,7 @@
                 mockTaskOrganizer,
                 mockDisplayController,
                 mockShellController,
+                displayInsetsController,
                 mockSyncQueue,
                 mockTransitions,
                 Optional.of(mockDesktopTasksController),
@@ -131,6 +142,11 @@
         whenever(mockInputMonitor.inputChannel).thenReturn(inputChannels[1])
 
         shellInit.init()
+
+        val listenerCaptor =
+                argumentCaptor<DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener>()
+        verify(displayInsetsController).addInsetsChangedListener(anyInt(), listenerCaptor.capture())
+        desktopModeOnInsetsChangedListener = listenerCaptor.firstValue
     }
 
     @Test
@@ -274,6 +290,67 @@
         verify(decoration).addTransitionPausingRelayout(transition)
     }
 
+    @Test
+    fun testRelayoutRunsWhenStatusBarsInsetsSourceVisibilityChanges() {
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM, focused = true)
+        val decoration = setUpMockDecorationForTask(task)
+
+        onTaskOpening(task)
+
+        // Add status bar insets source
+        val insetsState = InsetsState()
+        val statusBarInsetsSourceId = 0
+        val statusBarInsetsSource = InsetsSource(statusBarInsetsSourceId, statusBars())
+        statusBarInsetsSource.isVisible = false
+        insetsState.addSource(statusBarInsetsSource)
+
+        desktopModeOnInsetsChangedListener.insetsChanged(insetsState)
+
+        // Verify relayout occurs when status bar inset visibility changes
+        verify(decoration, times(1)).relayout(task)
+    }
+
+    @Test
+    fun testRelayoutDoesNotRunWhenNonStatusBarsInsetsSourceVisibilityChanges() {
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM, focused = true)
+        val decoration = setUpMockDecorationForTask(task)
+
+        onTaskOpening(task)
+
+        // Add navigation bar insets source
+        val insetsState = InsetsState()
+        val navigationBarInsetsSourceId = 1
+        val navigationBarInsetsSource = InsetsSource(navigationBarInsetsSourceId, navigationBars())
+        navigationBarInsetsSource.isVisible = false
+        insetsState.addSource(navigationBarInsetsSource)
+
+        desktopModeOnInsetsChangedListener.insetsChanged(insetsState)
+
+        // Verify relayout does not occur when non-status bar inset changes visibility
+        verify(decoration, never()).relayout(task)
+    }
+
+    @Test
+    fun testRelayoutDoesNotRunWhenNonStatusBarsInsetSourceVisibilityDoesNotChange() {
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM, focused = true)
+        val decoration = setUpMockDecorationForTask(task)
+
+        onTaskOpening(task)
+
+        // Add status bar insets source
+        val insetsState = InsetsState()
+        val statusBarInsetsSourceId = 0
+        val statusBarInsetsSource = InsetsSource(statusBarInsetsSourceId, statusBars())
+        statusBarInsetsSource.isVisible = false
+        insetsState.addSource(statusBarInsetsSource)
+
+        desktopModeOnInsetsChangedListener.insetsChanged(insetsState)
+        desktopModeOnInsetsChangedListener.insetsChanged(insetsState)
+
+        // Verify relayout runs only once when status bar inset visibility changes.
+        verify(decoration, times(1)).relayout(task)
+    }
+
     private fun onTaskOpening(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) {
         desktopModeWindowDecorViewModel.onTaskOpening(
                 task,
@@ -313,6 +390,8 @@
         whenever(mockDesktopModeWindowDecorFactory.create(
                 any(), any(), any(), eq(task), any(), any(), any(), any(), any())
         ).thenReturn(decoration)
+        decoration.mTaskInfo = task
+        whenever(decoration.isFocused).thenReturn(task.isFocused)
         return decoration
     }
 
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 966a99ee..8061aa3 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,12 +17,19 @@
 package com.android.wm.shell.windowdecor;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowInsets.Type.captionBar;
+import static android.view.WindowInsets.Type.mandatorySystemGestures;
+import static android.view.WindowInsets.Type.statusBars;
 
+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;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static junit.framework.Assert.assertTrue;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -36,6 +43,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;
@@ -48,6 +56,7 @@
 import android.util.DisplayMetrics;
 import android.view.AttachedSurfaceControl;
 import android.view.Display;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost;
 import android.view.View;
@@ -59,10 +68,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;
@@ -89,6 +100,7 @@
     private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400);
     private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60);
     private static final int CORNER_RADIUS = 20;
+    private static final int STATUS_BAR_INSET_SOURCE_ID = 0;
 
     private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult =
             new WindowDecoration.RelayoutResult<>();
@@ -113,6 +125,7 @@
     private final List<SurfaceControl.Transaction> mMockSurfaceControlTransactions =
             new ArrayList<>();
     private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>();
+    private final InsetsState mInsetsState = new InsetsState();
     private SurfaceControl.Transaction mMockSurfaceControlStartT;
     private SurfaceControl.Transaction mMockSurfaceControlFinishT;
     private SurfaceControl.Transaction mMockSurfaceControlAddWindowT;
@@ -136,6 +149,11 @@
                 .create(any(), any(), any());
         when(mMockSurfaceControlViewHost.getRootSurfaceControl())
                 .thenReturn(mMockRootSurfaceControl);
+        when(mMockView.findViewById(anyInt())).thenReturn(mMockView);
+
+        // Add status bar inset so that WindowDecoration does not think task is in immersive mode
+        mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, statusBars()).setVisible(true);
+        doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt());
     }
 
     @Test
@@ -201,12 +219,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)
@@ -255,8 +269,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);
@@ -502,6 +514,142 @@
         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 testInsetsAddedWhenCaptionIsVisible() {
+        final Display defaultDisplay = mock(Display.class);
+        doReturn(defaultDisplay).when(mMockDisplayController)
+                .getDisplay(Display.DEFAULT_DISPLAY);
+
+        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+                new ActivityManager.TaskDescription.Builder();
+        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+                .setDisplayId(Display.DEFAULT_DISPLAY)
+                .setTaskDescriptionBuilder(taskDescriptionBuilder)
+                .setVisible(true)
+                .build();
+        final SurfaceControl taskSurface = mock(SurfaceControl.class);
+        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
+
+        assertTrue(mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, statusBars())
+                .isVisible());
+        assertTrue(mInsetsState.sourceSize() == 1);
+        assertTrue(mInsetsState.sourceAt(0).getType() == statusBars());
+
+        windowDecor.relayout(taskInfo);
+
+        verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
+                eq(0) /* index */, eq(captionBar()), any());
+        verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
+                eq(0) /* index */, eq(mandatorySystemGestures()), any());
+    }
+
+    @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();
+    }
+
+
+    @Test
+    public void testInsetsRemovedWhenCaptionIsHidden() {
+        final Display defaultDisplay = mock(Display.class);
+        doReturn(defaultDisplay).when(mMockDisplayController)
+                .getDisplay(Display.DEFAULT_DISPLAY);
+
+        mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, captionBar()).setVisible(false);
+
+        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+                new ActivityManager.TaskDescription.Builder();
+        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+                .setDisplayId(Display.DEFAULT_DISPLAY)
+                .setTaskDescriptionBuilder(taskDescriptionBuilder)
+                .setVisible(true)
+                .build();
+        final SurfaceControl taskSurface = mock(SurfaceControl.class);
+        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
+
+        windowDecor.relayout(taskInfo);
+
+        verify(mMockWindowContainerTransaction).removeInsetsSource(eq(taskInfo.token), any(),
+                eq(0) /* index */, eq(captionBar()));
+        verify(mMockWindowContainerTransaction).removeInsetsSource(eq(taskInfo.token), any(),
+                eq(0) /* index */, eq(mandatorySystemGestures()));
+    }
+
     private TestWindowDecoration createWindowDecoration(
             ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
         return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
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/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..5b88079 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1473,8 +1473,7 @@
      * Returns the volume group id associated to the given {@link AudioAttributes}.
      *
      * @param attributes The {@link AudioAttributes} to consider.
-     * @return {@link android.media.audiopolicy.AudioVolumeGroup} id supporting the given
-     * {@link AudioAttributes} if found,
+     * @return audio volume group id supporting the given {@link AudioAttributes} if found,
      * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise.
      */
     public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
@@ -1589,7 +1588,7 @@
      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
      * the volume group id supporting the given {@link AudioAttributes}.
      *
-     * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+     * @param groupId of the audio volume group to consider.
      * @param direction The direction to adjust the volume. One of
      *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
      *            {@link #ADJUST_SAME}.
@@ -1633,8 +1632,8 @@
      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
      * the volume group id supporting the given {@link AudioAttributes}.
      *
-     * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
-     * @return The mute state for the given {@link android.media.audiopolicy.AudioVolumeGroup} id.
+     * @param groupId of the audio volume group to consider.
+     * @return The mute state for the given audio volume group id.
      * @see #adjustVolumeGroupVolume(int, int, int)
      */
     public boolean isVolumeGroupMuted(int groupId) {
@@ -4659,24 +4658,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/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/projection/OWNERS b/media/java/android/media/projection/OWNERS
index cc9be9c..880ec8f 100644
--- a/media/java/android/media/projection/OWNERS
+++ b/media/java/android/media/projection/OWNERS
@@ -4,3 +4,4 @@
 santoscordon@google.com
 chaviw@google.com
 nmusgrave@google.com
+dakinola@google.com
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..2db4be8 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -939,9 +939,8 @@
                 type = TYPE_HDMI;
                 isHardwareInput = true;
                 hdmiConnectionRelativePosition = getRelativePosition(mContext, mHdmiDeviceInfo);
-                isConnectedToHdmiSwitch =
-                        hdmiConnectionRelativePosition
-                                != HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW;
+                isConnectedToHdmiSwitch = hdmiConnectionRelativePosition
+                                == HdmiUtils.HDMI_RELATIVE_POSITION_BELOW;
             } 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/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/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index 222877b..88f12046 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -102,6 +102,8 @@
         <item name="android:layout_height">36dp</item>
         <item name="android:textAllCaps">false</item>
         <item name="android:textSize">14sp</item>
+        <item name="android:paddingLeft">6dp</item>
+        <item name="android:paddingRight">6dp</item>
         <item name="android:background">@drawable/btn_negative_multiple_devices</item>
         <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
     </style>
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/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..976a3ad 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,6 +167,7 @@
             dest.writeString(label.toString());
             Bitmap bmp = getBitmapFromDrawable(icon);
             dest.writeParcelable(bmp, 0);
+            dest.writeInt(iconSize);
         }
 
         private Bitmap getBitmapFromDrawable(Drawable drawable) {
@@ -174,6 +181,14 @@
             // bitmap held within
             drawable.draw(canvas);
 
+            // Scale it down if the icon is too large
+            if ((bmp.getWidth() > iconSize * 2) || (bmp.getHeight() > iconSize * 2)) {
+                Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp, iconSize, iconSize, true);
+                if (scaledBitmap != bmp) {
+                    bmp.recycle();
+                }
+                return scaledBitmap;
+            }
             return bmp;
         }
 
@@ -241,7 +256,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/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/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/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 412a342..ce0772f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -54,6 +54,7 @@
 import com.android.internal.util.UserIcons;
 import com.android.launcher3.icons.BaseIconFactory.IconOptions;
 import com.android.launcher3.icons.IconFactory;
+import com.android.launcher3.util.UserIconInfo;
 import com.android.settingslib.drawable.UserIconDrawable;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.settingslib.utils.BuildCompatUtils;
@@ -67,8 +68,7 @@
     static final String STORAGE_MANAGER_ENABLED_PROPERTY =
             "ro.storage_manager.enabled";
 
-    @VisibleForTesting
-    static final String INCOMPATIBLE_CHARGER_WARNING_DISABLED =
+    public static final String INCOMPATIBLE_CHARGER_WARNING_DISABLED =
             "incompatible_charger_warning_disabled";
 
     private static Signature[] sSystemSignature;
@@ -598,15 +598,25 @@
 
     /** Get the corresponding adaptive icon drawable. */
     public static Drawable getBadgedIcon(Context context, Drawable icon, UserHandle user) {
-        UserManager um = context.getSystemService(UserManager.class);
-        boolean isClone = um.getProfiles(user.getIdentifier()).stream()
-                .anyMatch(profile ->
-                        profile.isCloneProfile() && profile.id == user.getIdentifier());
+        int userType = UserIconInfo.TYPE_MAIN;
+        try {
+            UserInfo ui = context.getSystemService(UserManager.class).getUserInfo(
+                    user.getIdentifier());
+            if (ui != null) {
+                if (ui.isCloneProfile()) {
+                    userType = UserIconInfo.TYPE_CLONED;
+                } else if (ui.isManagedProfile()) {
+                    userType = UserIconInfo.TYPE_WORK;
+                }
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
         try (IconFactory iconFactory = IconFactory.obtain(context)) {
             return iconFactory
                     .createBadgedIconBitmap(
                             icon,
-                            new IconOptions().setUser(user).setIsCloneProfile(isClone))
+                            new IconOptions().setUser(new UserIconInfo(user, userType)))
                     .newIcon(context);
         }
     }
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/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index 7f1f3f6..2032328 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -110,7 +110,8 @@
     }
 
     /**
-     * Determine whether the device is plugged in wireless. */
+     * Determine whether the device is plugged in wireless.
+     */
     public boolean isPluggedInWireless() {
         return plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
     }
@@ -185,6 +186,22 @@
         return status == BATTERY_STATUS_FULL || level >= 100;
     }
 
+    /**
+     * Whether or not the device is charged. Note that some devices never return 100% for battery
+     * level, so this allows either battery level or status to determine if the battery is charged.
+     *
+     * @param status the value from extra {@link BatteryManager.EXTRA_STATUS} of
+     *     {@link Intent.ACTION_BATTERY_CHANGED} intent
+     * @param level the value from extra {@link BatteryManager.EXTRA_LEVEL} of
+     *     {@link Intent.ACTION_BATTERY_CHANGED} intent
+     * @param scale the value from extra {@link BatteryManager.EXTRA_SCALE} of
+     *     {@link Intent.ACTION_BATTERY_CHANGED} intent
+     */
+    public static boolean isCharged(int status, int level, int scale) {
+        var batteryLevel = getBatteryLevel(level, scale);
+        return isCharged(status, batteryLevel);
+    }
+
     /** Gets the battery level from the intent. */
     public static int getBatteryLevel(Intent batteryChangedIntent) {
         if (batteryChangedIntent == null) {
@@ -193,6 +210,14 @@
         final int level =
                 batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, BATTERY_LEVEL_UNKNOWN);
         final int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
+        return getBatteryLevel(level, scale);
+    }
+
+    /**
+     * Gets the battery level from the value of {@link Intent.BATTERY_CHANGED_INTENT}'s EXTRA_LEVEL
+     * and EXTRA_SCALE.
+     */
+    public static int getBatteryLevel(int level, int scale) {
         return scale == 0
                 ? BATTERY_LEVEL_UNKNOWN
                 : Math.round((level / (float) scale) * 100f);
@@ -253,11 +278,22 @@
      *
      * @param batteryChangedIntent the ACTION_BATTERY_CHANGED intent
      * @return {@code true} if the battery level is less or equal to {@link
-     *     SEVERE_LOW_BATTERY_THRESHOLD}
+     * SEVERE_LOW_BATTERY_THRESHOLD}
      */
     public static boolean isSevereLowBattery(Intent batteryChangedIntent) {
-        int level = getBatteryLevel(batteryChangedIntent);
-        return level <= SEVERE_LOW_BATTERY_THRESHOLD;
+        int batteryLevel = getBatteryLevel(batteryChangedIntent);
+        return isSevereLowBattery(batteryLevel);
+    }
+
+    /**
+     * Whether the battery is severe low or not.
+     *
+     * @param batteryLevel the value of battery level
+     * @return {@code true} if the battery level is less or equal to {@link
+     * SEVERE_LOW_BATTERY_THRESHOLD}
+     */
+    public static boolean isSevereLowBattery(int batteryLevel) {
+        return batteryLevel <= SEVERE_LOW_BATTERY_THRESHOLD;
     }
 
     /**
@@ -265,11 +301,21 @@
      *
      * @param batteryChangedIntent the ACTION_BATTERY_CHANGED intent
      * @return {@code true} if the battery level is less or equal to {@link
-     *     EXTREME_LOW_BATTERY_THRESHOLD}
+     * EXTREME_LOW_BATTERY_THRESHOLD}
      */
     public static boolean isExtremeLowBattery(Intent batteryChangedIntent) {
         int level = getBatteryLevel(batteryChangedIntent);
-        return level <= EXTREME_LOW_BATTERY_THRESHOLD;
+        return isExtremeLowBattery(level);
+    }
+
+    /**
+     * Whether the battery is extreme low or not.
+     *
+     * @return {@code true} if the {@code batteryLevel} is less or equal to
+     * {@link EXTREME_LOW_BATTERY_THRESHOLD}
+     */
+    public static boolean isExtremeLowBattery(int batteryLevel) {
+        return batteryLevel <= EXTREME_LOW_BATTERY_THRESHOLD;
     }
 
     /**
@@ -277,7 +323,7 @@
      *
      * @param batteryChangedIntent the ACTION_BATTERY_CHANGED intent
      * @return {@code true} if the battery defender is enabled. It could be dock defend, dwell
-     *     defend, or temp defend
+     * defend, or temp defend
      */
     public static boolean isBatteryDefender(Intent batteryChangedIntent) {
         int chargingStatus =
@@ -298,9 +344,8 @@
     }
 
     /**
-     * Gets the max charging current and max charging voltage form {@link
-     * Intent.ACTION_BATTERY_CHANGED} and calculates the charging speed based on the {@link
-     * R.integer.config_chargingSlowlyThreshold} and {@link R.integer.config_chargingFastThreshold}.
+     * Calculates the charging speed based on the {@link R.integer.config_chargingSlowlyThreshold}
+     * and {@link R.integer.config_chargingFastThreshold}.
      *
      * @param context the application context
      * @param batteryChangedIntent the intent from {@link Intent.ACTION_BATTERY_CHANGED}
@@ -308,7 +353,29 @@
      *     CHARGING_SLOWLY} or {@link CHARGING_UNKNOWN}
      */
     public static int getChargingSpeed(Context context, Intent batteryChangedIntent) {
-        final int maxChargingMicroWatt = calculateMaxChargingMicroWatt(batteryChangedIntent);
+        final int maxChargingMicroCurrent =
+                batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, -1);
+        int maxChargingMicroVolt = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_VOLTAGE, -1);
+
+        return calculateChargingSpeed(context, maxChargingMicroCurrent, maxChargingMicroVolt);
+    }
+
+    /**
+     * Calculates the charging speed based on the {@link R.integer.config_chargingSlowlyThreshold}
+     * and {@link R.integer.config_chargingFastThreshold}.
+     *
+     * @param maxChargingMicroCurrent the max charging micro current that is retrieved form the
+     *     extra of {@link Intent.Action_BATTERY_CHANGED}
+     * @param maxChargingMicroVolt the max charging micro voltage that is retrieved form the extra
+     *     of {@link Intent.Action_BATTERY_CHANGED}
+     * @return the charging speed. {@link CHARGING_REGULAR}, {@link CHARGING_FAST}, {@link
+     *     CHARGING_SLOWLY} or {@link CHARGING_UNKNOWN}
+     */
+    public static int calculateChargingSpeed(
+            Context context, int maxChargingMicroCurrent, int maxChargingMicroVolt) {
+        final int maxChargingMicroWatt =
+                calculateMaxChargingMicroWatt(maxChargingMicroCurrent, maxChargingMicroVolt);
+
         if (maxChargingMicroWatt <= 0) {
             return CHARGING_UNKNOWN;
         } else if (maxChargingMicroWatt
@@ -326,6 +393,12 @@
         final int maxChargingMicroAmp =
                 batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, -1);
         int maxChargingMicroVolt = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_VOLTAGE, -1);
+
+        return calculateMaxChargingMicroWatt(maxChargingMicroAmp, maxChargingMicroVolt);
+    }
+
+    private static int calculateMaxChargingMicroWatt(int maxChargingMicroAmp,
+            int maxChargingMicroVolt) {
         if (maxChargingMicroVolt <= 0) {
             maxChargingMicroVolt = DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 41afc7b..a63bbdf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -26,6 +26,7 @@
 
 import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.media.MediaRoute2Info;
@@ -51,6 +52,34 @@
 
     private final DeviceIconUtil mDeviceIconUtil;
 
+    /** Returns the device name for the given {@code routeInfo}. */
+    public static String getSystemRouteNameFromType(
+            @NonNull Context context, @NonNull MediaRoute2Info routeInfo) {
+        CharSequence name;
+        switch (routeInfo.getType()) {
+            case TYPE_WIRED_HEADSET:
+            case TYPE_WIRED_HEADPHONES:
+            case TYPE_USB_DEVICE:
+            case TYPE_USB_HEADSET:
+            case TYPE_USB_ACCESSORY:
+                name = context.getString(R.string.media_transfer_wired_usb_device_name);
+                break;
+            case TYPE_DOCK:
+                name = context.getString(R.string.media_transfer_dock_speaker_device_name);
+                break;
+            case TYPE_BUILTIN_SPEAKER:
+                name = context.getString(R.string.media_transfer_this_device_name);
+                break;
+            case TYPE_HDMI:
+                name = context.getString(R.string.media_transfer_external_device_name);
+                break;
+            default:
+                name = context.getString(R.string.media_transfer_default_device_name);
+                break;
+        }
+        return name.toString();
+    }
+
     PhoneMediaDevice(Context context, MediaRoute2Info info, String packageName) {
         this(context, info, packageName, null);
     }
@@ -69,29 +98,7 @@
     @SuppressWarnings("NewApi")
     @Override
     public String getName() {
-        CharSequence name;
-        switch (mRouteInfo.getType()) {
-            case TYPE_WIRED_HEADSET:
-            case TYPE_WIRED_HEADPHONES:
-            case TYPE_USB_DEVICE:
-            case TYPE_USB_HEADSET:
-            case TYPE_USB_ACCESSORY:
-                name = mContext.getString(R.string.media_transfer_wired_usb_device_name);
-                break;
-            case TYPE_DOCK:
-                name = mContext.getString(R.string.media_transfer_dock_speaker_device_name);
-                break;
-            case TYPE_BUILTIN_SPEAKER:
-                name = mContext.getString(R.string.media_transfer_this_device_name);
-                break;
-            case TYPE_HDMI:
-                name = mContext.getString(R.string.media_transfer_external_device_name);
-                break;
-            default:
-                name = mContext.getString(R.string.media_transfer_default_device_name);
-                break;
-        }
-        return name.toString();
+        return getSystemRouteNameFromType(mContext, mRouteInfo);
     }
 
     @Override
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/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 29f27f7..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;
 
@@ -236,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 34d3d44..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;
@@ -3878,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;
 
@@ -5935,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;
                 }
 
@@ -6004,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 9ddc976a..7bca944 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -98,8 +98,6 @@
                     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,
@@ -735,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,
@@ -805,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 e40fcb2..f65f5a3 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -60,6 +60,7 @@
             // except for SystemUI-core.
             // Copied from compose/features/Android.bp.
             static_libs: [
+                "CommunalLayoutLib",
                 "PlatformComposeCore",
 
                 "androidx.compose.runtime_runtime",
@@ -163,6 +164,7 @@
         "SystemUISharedLib",
         "SystemUI-statsd",
         "SettingsLib",
+        "com_android_systemui_communal_flags_lib",
         "com_android_systemui_flags_lib",
         "androidx.core_core-ktx",
         "androidx.viewpager2_viewpager2",
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/aconfig/Android.bp b/packages/SystemUI/aconfig/Android.bp
index c1390b2..b18c790 100644
--- a/packages/SystemUI/aconfig/Android.bp
+++ b/packages/SystemUI/aconfig/Android.bp
@@ -11,3 +11,16 @@
     name: "com_android_systemui_flags_lib",
     aconfig_declarations: "com_android_systemui_flags",
 }
+
+aconfig_declarations {
+    name: "com_android_systemui_communal_flags",
+    package: "com.android.systemui.communal",
+    srcs: [
+        "communal.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "com_android_systemui_communal_flags_lib",
+    aconfig_declarations: "com_android_systemui_communal_flags",
+}
diff --git a/packages/SystemUI/aconfig/communal.aconfig b/packages/SystemUI/aconfig/communal.aconfig
new file mode 100644
index 0000000..8ecb984
--- /dev/null
+++ b/packages/SystemUI/aconfig/communal.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.systemui.communal"
+
+flag {
+    name: "communal_hub"
+    namespace: "communal"
+    description: "Enables the communal hub experience"
+    bug: "304584416"
+}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 18117a8..2509cfd 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -21,3 +21,11 @@
         "(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 4aac279..4ea57a8 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -893,7 +893,7 @@
                 return
             }
 
-            Log.i(TAG, "Remote animation timed out")
+            Log.wtf(TAG, "Remote animation timed out")
             timedOut = true
 
             if (DEBUG_LAUNCH_ANIMATION) {
diff --git a/packages/SystemUI/communal/layout/Android.bp b/packages/SystemUI/communal/layout/Android.bp
new file mode 100644
index 0000000..88dad66
--- /dev/null
+++ b/packages/SystemUI/communal/layout/Android.bp
@@ -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 {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+    name: "CommunalLayoutLib",
+    srcs: [
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "androidx.arch.core_core-runtime",
+        "androidx.compose.animation_animation-graphics",
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.material3_material3",
+        "jsr330",
+        "kotlinx-coroutines-android",
+        "kotlinx-coroutines-core",
+    ],
+    manifest: "AndroidManifest.xml",
+    kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/packages/SystemUI/communal/layout/AndroidManifest.xml b/packages/SystemUI/communal/layout/AndroidManifest.xml
new file mode 100644
index 0000000..141be07
--- /dev/null
+++ b/packages/SystemUI/communal/layout/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?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.systemui.communal.layout" />
diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.kt
new file mode 100644
index 0000000..df87d19d
--- /dev/null
+++ b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.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.layout
+
+import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard
+
+/** Computes the arrangement of cards. */
+class CommunalLayoutEngine {
+    companion object {
+        /**
+         * Determines the size that each card should be rendered in, and distributes the cards into
+         * columns.
+         *
+         * Returns a nested list where the outer list contains columns, and the inner list contains
+         * cards in each column.
+         *
+         * Currently treats the first supported size as the size to be rendered in, ignoring other
+         * supported sizes.
+         */
+        fun distributeCardsIntoColumns(
+            cards: List<CommunalGridLayoutCard>,
+        ): List<List<CommunalGridLayoutCardInfo>> {
+            val result = ArrayList<ArrayList<CommunalGridLayoutCardInfo>>()
+
+            var capacityOfLastColumn = 0
+            for (card in cards) {
+                val cardSize = card.supportedSizes.first()
+                if (capacityOfLastColumn >= cardSize.value) {
+                    // Card fits in last column
+                    capacityOfLastColumn -= cardSize.value
+                } else {
+                    // Create a new column
+                    result.add(arrayListOf())
+                    capacityOfLastColumn = CommunalGridLayoutCard.Size.FULL.value - cardSize.value
+                }
+
+                result.last().add(CommunalGridLayoutCardInfo(card, cardSize))
+            }
+
+            return result
+        }
+    }
+
+    /**
+     * A data class that wraps around a [CommunalGridLayoutCard] and also contains the size that the
+     * card should be rendered in.
+     */
+    data class CommunalGridLayoutCardInfo(
+        val card: CommunalGridLayoutCard,
+        val size: CommunalGridLayoutCard.Size,
+    )
+}
diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.kt
new file mode 100644
index 0000000..4ed78b3
--- /dev/null
+++ b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.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.systemui.communal.layout.ui.compose
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.android.systemui.communal.layout.CommunalLayoutEngine
+import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard
+import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutConfig
+
+/**
+ * An arrangement of cards with a horizontal scroll, where each card is displayed in the right size
+ * and follows a specific order based on its priority, ensuring a seamless layout without any gaps.
+ */
+@Composable
+fun CommunalGridLayout(
+    modifier: Modifier,
+    layoutConfig: CommunalGridLayoutConfig,
+    communalCards: List<CommunalGridLayoutCard>,
+) {
+    val columns = CommunalLayoutEngine.distributeCardsIntoColumns(communalCards)
+    LazyRow(
+        modifier = modifier.height(layoutConfig.gridHeight),
+        horizontalArrangement = Arrangement.spacedBy(layoutConfig.gridGutter),
+    ) {
+        for (column in columns) {
+            item {
+                Column(
+                    modifier = Modifier.width(layoutConfig.cardWidth),
+                    verticalArrangement = Arrangement.spacedBy(layoutConfig.gridGutter),
+                ) {
+                    for (cardInfo in column) {
+                        Row(
+                            modifier = Modifier.height(layoutConfig.cardHeight(cardInfo.size)),
+                        ) {
+                            cardInfo.card.Content(Modifier.fillMaxSize())
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.kt
new file mode 100644
index 0000000..ac8aa67
--- /dev/null
+++ b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.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.systemui.communal.layout.ui.compose.config
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+
+/** A card that hosts content to be rendered in the communal grid layout. */
+abstract class CommunalGridLayoutCard {
+    /**
+     * Content to be hosted by the card.
+     *
+     * To host non-Compose views, see
+     * https://developer.android.com/jetpack/compose/migrate/interoperability-apis/views-in-compose.
+     */
+    @Composable abstract fun Content(modifier: Modifier)
+
+    /**
+     * Sizes supported by the card.
+     *
+     * If multiple sizes are available, they should be ranked in order of preference, from most to
+     * least preferred.
+     */
+    abstract val supportedSizes: List<Size>
+
+    /**
+     * Priority of the content hosted by the card.
+     *
+     * The value of priority is relative to other cards. Cards with a higher priority are generally
+     * ordered first.
+     */
+    open val priority: Int = 0
+
+    /**
+     * Size of the card.
+     *
+     * @param value A numeric value that represents the size. Must be less than or equal to
+     *   [Size.FULL].
+     */
+    enum class Size(val value: Int) {
+        /** The card takes up full height of the grid layout. */
+        FULL(value = 6),
+
+        /** The card takes up half of the vertical space of the grid layout. */
+        HALF(value = 3),
+
+        /** The card takes up a third of the vertical space of the grid layout. */
+        THIRD(value = 2),
+    }
+}
diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt
new file mode 100644
index 0000000..143df83
--- /dev/null
+++ b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.layout.ui.compose.config
+
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.times
+
+/**
+ * Configurations of the communal grid layout.
+ *
+ * The communal grid layout follows Material Design's responsive layout grid (see
+ * https://m2.material.io/design/layout/responsive-layout-grid.html), in which the layout is divided
+ * up by columns and gutters, and each card occupies one or multiple columns.
+ */
+data class CommunalGridLayoutConfig(
+    /**
+     * Size in dp of each grid column.
+     *
+     * Every card occupies one or more grid columns, which means that the width of each card is
+     * influenced by the size of the grid columns.
+     */
+    val gridColumnSize: Dp,
+
+    /**
+     * Size in dp of each grid gutter.
+     *
+     * A gutter is the space between columns that helps separate content. This is, therefore, also
+     * the size of the gaps between cards, both horizontally and vertically.
+     */
+    val gridGutter: Dp,
+
+    /**
+     * Height in dp of the grid layout.
+     *
+     * Cards with a full size take up the entire height of the grid layout.
+     */
+    val gridHeight: Dp,
+
+    /**
+     * Number of grid columns that each card occupies.
+     *
+     * It's important to note that all the cards take up the same number of grid columns, or in
+     * simpler terms, they all have the same width.
+     */
+    val gridColumnsPerCard: Int,
+) {
+    /**
+     * Width in dp of each card.
+     *
+     * It's important to note that all the cards take up the same number of grid columns, or in
+     * simpler terms, they all have the same width.
+     */
+    val cardWidth = gridColumnSize * gridColumnsPerCard + gridGutter * (gridColumnsPerCard - 1)
+
+    /** Returns the height of a card in dp, based on its size. */
+    fun cardHeight(cardSize: CommunalGridLayoutCard.Size): Dp {
+        return when (cardSize) {
+            CommunalGridLayoutCard.Size.FULL -> cardHeightBy(denominator = 1)
+            CommunalGridLayoutCard.Size.HALF -> cardHeightBy(denominator = 2)
+            CommunalGridLayoutCard.Size.THIRD -> cardHeightBy(denominator = 3)
+        }
+    }
+
+    /** Returns the height of a card in dp when the layout is evenly divided by [denominator]. */
+    private fun cardHeightBy(denominator: Int): Dp {
+        return (gridHeight - (denominator - 1) * gridGutter) / denominator
+    }
+}
diff --git a/packages/SystemUI/communal/layout/tests/Android.bp b/packages/SystemUI/communal/layout/tests/Android.bp
new file mode 100644
index 0000000..a60b1de
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/Android.bp
@@ -0,0 +1,47 @@
+// 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 {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_test {
+    name: "CommunalLayoutLibTests",
+    srcs: [
+        "**/*.kt",
+    ],
+    static_libs: [
+        "CommunalLayoutLib",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "frameworks-base-testutils",
+        "junit",
+        "kotlinx_coroutines_test",
+        "mockito-target-extended-minus-junit4",
+        "platform-test-annotations",
+        "testables",
+        "truth-prebuilt",
+    ],
+    libs: [
+        "android.test.mock",
+        "android.test.base",
+        "android.test.runner",
+    ],
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+    manifest: "AndroidManifest.xml",
+}
diff --git a/packages/SystemUI/communal/layout/tests/AndroidManifest.xml b/packages/SystemUI/communal/layout/tests/AndroidManifest.xml
new file mode 100644
index 0000000..b19007c
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.communal.layout.tests">
+
+    <application android:debuggable="true" android:largeHeap="true">
+        <uses-library android:name="android.test.mock" />
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.testing.TestableInstrumentation"
+        android:targetPackage="com.android.systemui.communal.layout.tests"
+        android:label="Tests for CommunalLayoutLib">
+    </instrumentation>
+
+</manifest>
diff --git a/packages/SystemUI/communal/layout/tests/AndroidTest.xml b/packages/SystemUI/communal/layout/tests/AndroidTest.xml
new file mode 100644
index 0000000..1352b23
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration description="Runs tests for CommunalLayoutLib">
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="install-arg" value="-t" />
+        <option name="test-file-name" value="CommunalLayoutLibTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="framework-base-presubmit" />
+    <option name="test-tag" value="CommunalLayoutLibTests" />
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.systemui.communal.layout.tests" />
+        <option name="runner" value="android.testing.TestableInstrumentation" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+
+</configuration>
diff --git a/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt
new file mode 100644
index 0000000..fdf65f5
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt
@@ -0,0 +1,99 @@
+package com.android.systemui.communal.layout
+
+import androidx.compose.material3.Card
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalLayoutEngineTest {
+    @Test
+    fun distribution_fullLayout() {
+        val cards =
+            listOf(
+                generateCard(CommunalGridLayoutCard.Size.FULL),
+                generateCard(CommunalGridLayoutCard.Size.HALF),
+                generateCard(CommunalGridLayoutCard.Size.HALF),
+                generateCard(CommunalGridLayoutCard.Size.THIRD),
+                generateCard(CommunalGridLayoutCard.Size.THIRD),
+                generateCard(CommunalGridLayoutCard.Size.THIRD),
+            )
+        val expected =
+            listOf(
+                listOf(
+                    CommunalGridLayoutCard.Size.FULL,
+                ),
+                listOf(
+                    CommunalGridLayoutCard.Size.HALF,
+                    CommunalGridLayoutCard.Size.HALF,
+                ),
+                listOf(
+                    CommunalGridLayoutCard.Size.THIRD,
+                    CommunalGridLayoutCard.Size.THIRD,
+                    CommunalGridLayoutCard.Size.THIRD,
+                ),
+            )
+
+        assertDistribution(cards, expected)
+    }
+
+    @Test
+    fun distribution_layoutWithGaps() {
+        val cards =
+            listOf(
+                generateCard(CommunalGridLayoutCard.Size.HALF),
+                generateCard(CommunalGridLayoutCard.Size.THIRD),
+                generateCard(CommunalGridLayoutCard.Size.HALF),
+                generateCard(CommunalGridLayoutCard.Size.FULL),
+                generateCard(CommunalGridLayoutCard.Size.THIRD),
+            )
+        val expected =
+            listOf(
+                listOf(
+                    CommunalGridLayoutCard.Size.HALF,
+                    CommunalGridLayoutCard.Size.THIRD,
+                ),
+                listOf(
+                    CommunalGridLayoutCard.Size.HALF,
+                ),
+                listOf(
+                    CommunalGridLayoutCard.Size.FULL,
+                ),
+                listOf(
+                    CommunalGridLayoutCard.Size.THIRD,
+                ),
+            )
+
+        assertDistribution(cards, expected)
+    }
+
+    private fun assertDistribution(
+        cards: List<CommunalGridLayoutCard>,
+        expected: List<List<CommunalGridLayoutCard.Size>>,
+    ) {
+        val result = CommunalLayoutEngine.distributeCardsIntoColumns(cards)
+
+        for (c in expected.indices) {
+            for (r in expected[c].indices) {
+                assertThat(result[c][r].size).isEqualTo(expected[c][r])
+            }
+        }
+    }
+
+    private fun generateCard(size: CommunalGridLayoutCard.Size): CommunalGridLayoutCard {
+        return object : CommunalGridLayoutCard() {
+            override val supportedSizes = listOf(size)
+
+            @Composable
+            override fun Content(modifier: Modifier) {
+                Card(modifier = modifier, content = {})
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt
new file mode 100644
index 0000000..946eeec
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt
@@ -0,0 +1,63 @@
+package com.android.systemui.communal.layout.ui.compose.config
+
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalGridLayoutConfigTest {
+    @Test
+    fun cardWidth() {
+        Truth.assertThat(
+                CommunalGridLayoutConfig(
+                        gridColumnSize = 5.dp,
+                        gridGutter = 3.dp,
+                        gridHeight = 17.dp,
+                        gridColumnsPerCard = 1,
+                    )
+                    .cardWidth
+            )
+            .isEqualTo(5.dp)
+
+        Truth.assertThat(
+                CommunalGridLayoutConfig(
+                        gridColumnSize = 5.dp,
+                        gridGutter = 3.dp,
+                        gridHeight = 17.dp,
+                        gridColumnsPerCard = 2,
+                    )
+                    .cardWidth
+            )
+            .isEqualTo(13.dp)
+
+        Truth.assertThat(
+                CommunalGridLayoutConfig(
+                        gridColumnSize = 5.dp,
+                        gridGutter = 3.dp,
+                        gridHeight = 17.dp,
+                        gridColumnsPerCard = 3,
+                    )
+                    .cardWidth
+            )
+            .isEqualTo(21.dp)
+    }
+
+    @Test
+    fun cardHeight() {
+        val config =
+            CommunalGridLayoutConfig(
+                gridColumnSize = 5.dp,
+                gridGutter = 2.dp,
+                gridHeight = 10.dp,
+                gridColumnsPerCard = 3,
+            )
+
+        Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.FULL)).isEqualTo(10.dp)
+        Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.HALF)).isEqualTo(4.dp)
+        Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.THIRD)).isEqualTo(2.dp)
+    }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
index 60c3fd3..88944f10 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -108,7 +108,7 @@
 ) {
     val fromScene = layoutImpl.state.transitionState.currentScene
     val isUserInput =
-        (layoutImpl.state.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
+        (layoutImpl.state.transitionState as? TransitionState.Transition)?.isUserInputDriven
             ?: false
 
     val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec
@@ -119,23 +119,9 @@
     val targetProgress = if (reversed) 0f else 1f
     val transition =
         if (reversed) {
-            OneOffTransition(
-                fromScene = target,
-                toScene = fromScene,
-                currentScene = target,
-                isUserInput,
-                isUserInputOngoing = false,
-                animatable,
-            )
+            OneOffTransition(target, fromScene, currentScene = target, isUserInput, animatable)
         } else {
-            OneOffTransition(
-                fromScene = fromScene,
-                toScene = target,
-                currentScene = target,
-                isUserInput,
-                isUserInputOngoing = false,
-                animatable,
-            )
+            OneOffTransition(fromScene, target, currentScene = target, isUserInput, animatable)
         }
 
     // Change the current layout state to use this new transition.
@@ -156,8 +142,7 @@
     override val fromScene: SceneKey,
     override val toScene: SceneKey,
     override val currentScene: SceneKey,
-    override val isInitiatedByUserInput: Boolean,
-    override val isUserInputOngoing: Boolean,
+    override val isUserInputDriven: Boolean,
     private val animatable: Animatable<Float, AnimationVector1D>,
 ) : TransitionState.Transition {
     override val progress: Float
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 3bcd920f..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
@@ -59,6 +60,17 @@
     /** The mapping between a scene and the values/state this element has in that scene, if any. */
     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)"
     }
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/ObservableTransitionState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index 1b79dbd..ccdec6e 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -52,14 +52,7 @@
          * scene, this value will remain true after the pointer is no longer touching the screen and
          * will be true in any transition created to animate back to the original position.
          */
-        val isInitiatedByUserInput: Boolean,
-
-        /**
-         * Whether user input is currently driving the transition. For example, if a user is
-         * dragging a pointer, this emits true. Once they lift their finger, this emits false while
-         * the transition completes/settles.
-         */
-        val isUserInputOngoing: Flow<Boolean>,
+        val isUserInputDriven: Boolean,
     ) : ObservableTransitionState()
 }
 
@@ -80,8 +73,7 @@
                             fromScene = state.fromScene,
                             toScene = state.toScene,
                             progress = snapshotFlow { state.progress },
-                            isInitiatedByUserInput = state.isInitiatedByUserInput,
-                            isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
+                            isUserInputDriven = state.isUserInputDriven,
                         )
                     }
                 }
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/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index b9f83c5..7a21211 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -70,9 +70,6 @@
         val progress: Float
 
         /** Whether the transition was triggered by user input rather than being programmatic. */
-        val isInitiatedByUserInput: Boolean
-
-        /** Whether user input is currently driving the transition. */
-        val isUserInputOngoing: Boolean
+        val isUserInputDriven: Boolean
     }
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
index e275fca..1cbfe30 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -66,7 +66,7 @@
     // swipe in the other direction.
     val startDragImmediately =
         state == transition &&
-            !transition.isUserInputOngoing &&
+            transition.isAnimatingOffset &&
             !currentScene.shouldEnableSwipes(orientation.opposite())
 
     // The velocity threshold at which the intent of the user is to swipe up or down. It is the same
@@ -126,7 +126,7 @@
 
     override val progress: Float
         get() {
-            val offset = if (isUserInputOngoing) dragOffset else offsetAnimatable.value
+            val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
             if (distance == 0f) {
                 // This can happen only if fromScene == toScene.
                 error(
@@ -137,15 +137,16 @@
             return offset / distance
         }
 
-    override val isInitiatedByUserInput = true
-
-    var _isUserInputOngoing by mutableStateOf(false)
-    override val isUserInputOngoing: Boolean
-        get() = _isUserInputOngoing
+    override val isUserInputDriven = true
 
     /** The current offset caused by the drag gesture. */
     var dragOffset by mutableFloatStateOf(0f)
 
+    /**
+     * Whether the offset is animated (the user lifted their finger) or if it is driven by gesture.
+     */
+    var isAnimatingOffset by mutableStateOf(false)
+
     /** The animatable used to animate the offset once the user lifted its finger. */
     val offsetAnimatable = Animatable(0f, visibilityThreshold = OffsetVisibilityThreshold)
 
@@ -208,11 +209,9 @@
     transition: SwipeTransition,
     orientation: Orientation,
 ) {
-    transition._isUserInputOngoing = true
-
     if (layoutImpl.state.transitionState == transition) {
         // This [transition] was already driving the animation: simply take over it.
-        if (!transition.isUserInputOngoing) {
+        if (transition.isAnimatingOffset) {
             // Stop animating and start from where the current offset. Setting the animation job to
             // `null` will effectively cancel the animation.
             transition.stopOffsetAnimation()
@@ -457,29 +456,30 @@
 ) {
     transition.startOffsetAnimation {
         launch {
-            if (transition.isUserInputOngoing) {
-                transition.offsetAnimatable.snapTo(transition.dragOffset)
-            }
-            transition._isUserInputOngoing = false
+                if (!transition.isAnimatingOffset) {
+                    transition.offsetAnimatable.snapTo(transition.dragOffset)
+                }
+                transition.isAnimatingOffset = true
 
-            transition.offsetAnimatable.animateTo(
-                targetOffset,
-                // TODO(b/290184746): Make this spring spec configurable.
-                spring(
-                    stiffness = Spring.StiffnessMediumLow,
-                    visibilityThreshold = OffsetVisibilityThreshold
-                ),
-                initialVelocity = initialVelocity,
-            )
+                transition.offsetAnimatable.animateTo(
+                    targetOffset,
+                    // TODO(b/290184746): Make this spring spec configurable.
+                    spring(
+                        stiffness = Spring.StiffnessMediumLow,
+                        visibilityThreshold = OffsetVisibilityThreshold
+                    ),
+                    initialVelocity = initialVelocity,
+                )
 
-            // Now that the animation is done, the state should be idle. Note that if the state
-            // was changed since this animation started, some external code changed it and we
-            // shouldn't do anything here. Note also that this job will be cancelled in the case
-            // where the user intercepts this swipe.
-            if (layoutImpl.state.transitionState == transition) {
-                layoutImpl.state.transitionState = TransitionState.Idle(targetScene)
+                // Now that the animation is done, the state should be idle. Note that if the state
+                // was changed since this animation started, some external code changed it and we
+                // shouldn't do anything here. Note also that this job will be cancelled in the case
+                // where the user intercepts this swipe.
+                if (layoutImpl.state.transitionState == transition) {
+                    layoutImpl.state.transitionState = TransitionState.Idle(targetScene)
+                }
             }
-        }
+            .also { it.invokeOnCompletion { transition.isAnimatingOffset = false } }
     }
 }
 
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 53ed2b5..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,
@@ -122,8 +122,7 @@
         assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
         assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
         assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
-        assertThat(transition.isInitiatedByUserInput).isTrue()
-        assertThat(transition.isUserInputOngoing).isTrue()
+        assertThat(transition.isUserInputDriven).isTrue()
 
         // Release the finger. We should now be animating back to A (currentScene = SceneA) given
         // that 55dp < positional threshold.
@@ -135,8 +134,7 @@
         assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
         assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
         assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
-        assertThat(transition.isInitiatedByUserInput).isTrue()
-        assertThat(transition.isUserInputOngoing).isFalse()
+        assertThat(transition.isUserInputDriven).isTrue()
 
         // Wait for the animation to finish. We should now be in scene A.
         rule.waitForIdle()
@@ -158,8 +156,7 @@
         assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
         assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
         assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
-        assertThat(transition.isInitiatedByUserInput).isTrue()
-        assertThat(transition.isUserInputOngoing).isTrue()
+        assertThat(transition.isUserInputDriven).isTrue()
 
         // Release the finger. We should now be animating to C (currentScene = SceneC) given
         // that 56dp >= positional threshold.
@@ -171,8 +168,7 @@
         assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
         assertThat(transition.currentScene).isEqualTo(TestScenes.SceneC)
         assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
-        assertThat(transition.isInitiatedByUserInput).isTrue()
-        assertThat(transition.isUserInputOngoing).isFalse()
+        assertThat(transition.isUserInputDriven).isTrue()
 
         // Wait for the animation to finish. We should now be in scene C.
         rule.waitForIdle()
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/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
index 5b4a8fb..3d670b8 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -64,6 +64,12 @@
         throwComposeUnavailableError()
     }
 
+    override fun createCommunalView(
+        context: Context,
+    ): View {
+        throwComposeUnavailableError()
+    }
+
     private fun throwComposeUnavailableError(): Nothing {
         error(
             "Compose is not available. Make sure to check isComposeAvailable() before calling any" +
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
index ac59989..7b11ac7 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
 import com.android.systemui.common.ui.compose.windowinsets.DisplayCutout
 import com.android.systemui.common.ui.compose.windowinsets.DisplayCutoutProvider
+import com.android.systemui.communal.ui.compose.CommunalHub
 import com.android.systemui.people.ui.compose.PeopleScreen
 import com.android.systemui.people.ui.viewmodel.PeopleViewModel
 import com.android.systemui.qs.footer.ui.compose.FooterActions
@@ -93,6 +94,12 @@
         }
     }
 
+    override fun createCommunalView(
+        context: Context,
+    ): View {
+        return ComposeView(context).apply { setContent { PlatformTheme { CommunalHub() } } }
+    }
+
     // TODO(b/298525212): remove once Compose exposes window inset bounds.
     private fun displayCutoutFromWindowInsets(
         scope: CoroutineScope,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
new file mode 100644
index 0000000..4d2978d
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -0,0 +1,22 @@
+package com.android.systemui.communal.ui.compose
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+
+@Composable
+fun CommunalHub(modifier: Modifier = Modifier) {
+    Box(
+        modifier = modifier.fillMaxSize().background(Color.White),
+    ) {
+        Text(
+            modifier = Modifier.align(Alignment.Center),
+            text = "Hello Communal!",
+        )
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
index 0d2ba28..d1c12ac 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
@@ -16,14 +16,8 @@
 
 package com.android.systemui.communal.ui.compose
 
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.scene.shared.model.Direction
@@ -51,13 +45,6 @@
 
     @Composable
     override fun SceneScope.Content(modifier: Modifier) {
-        Box(
-            modifier = modifier.fillMaxSize().background(Color.White),
-        ) {
-            Text(
-                modifier = Modifier.align(Alignment.Center),
-                text = "Hello Communal!",
-            )
-        }
+        CommunalHub(modifier)
     }
 }
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/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
index e12b7ea..73cb72c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -47,10 +47,10 @@
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import com.android.compose.theme.LocalAndroidColorScheme
-import com.android.systemui.res.R
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
 import com.android.systemui.people.ui.viewmodel.PeopleViewModel
+import com.android.systemui.res.R
 
 /**
  * Compose the screen associated to a [PeopleViewModel].
@@ -86,9 +86,9 @@
         modifier = Modifier.fillMaxSize(),
     ) {
         if (priorityTiles.isNotEmpty() || recentTiles.isNotEmpty()) {
-            PeopleScreenWithConversations(priorityTiles, recentTiles, viewModel::onTileClicked)
+            PeopleScreenWithConversations(priorityTiles, recentTiles, viewModel.onTileClicked)
         } else {
-            PeopleScreenEmpty(viewModel::onUserJourneyCancelled)
+            PeopleScreenEmpty(viewModel.onUserJourneyCancelled)
         }
     }
 }
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 6359ce60..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
@@ -158,8 +161,7 @@
                 fromScene = fromScene.toModel().key,
                 toScene = toScene.toModel().key,
                 progress = progress,
-                isInitiatedByUserInput = isInitiatedByUserInput,
-                isUserInputOngoing = isUserInputOngoing,
+                isUserInputDriven = isUserInputDriven,
             )
     }
 }
@@ -181,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/proguard_common.flags b/packages/SystemUI/proguard_common.flags
index be1e655..445bdc2 100644
--- a/packages/SystemUI/proguard_common.flags
+++ b/packages/SystemUI/proguard_common.flags
@@ -2,45 +2,17 @@
 
 # Needed to ensure callback field references are kept in their respective
 # owning classes when the downstream callback registrars only store weak refs.
-# TODO(b/264686688): Handle these cases with more targeted annotations.
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
-  private com.android.keyguard.KeyguardUpdateMonitorCallback *;
-  private com.android.systemui.privacy.PrivacyConfig$Callback *;
-  private com.android.systemui.privacy.PrivacyItemController$Callback *;
-  private com.android.systemui.settings.UserTracker$Callback *;
-  private com.android.systemui.statusbar.phone.StatusBarWindowCallback *;
-  private com.android.systemui.util.service.Observer$Callback *;
-  private com.android.systemui.util.service.ObservableServiceConnection$Callback *;
-}
-# Note that these rules are temporary companions to the above rules, required
-# for cases like Kotlin where fields with anonymous types use the anonymous type
-# rather than the supertype.
--if class * extends com.android.keyguard.KeyguardUpdateMonitorCallback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+# Note that we restrict this to SysUISingleton classes, as other registering
+# classes should either *always* unregister or *never* register from their
+# constructor. We also keep callback class names for easier debugging.
+-keepnames @com.android.systemui.util.annotations.WeaklyReferencedCallback class *
+-keepnames class * extends @com.android.systemui.util.annotations.WeaklyReferencedCallback **
+-if @com.android.systemui.util.annotations.WeaklyReferencedCallback class *
+-keepclassmembers,allowaccessmodification @com.android.systemui.dagger.SysUISingleton class * {
   <1> *;
 }
--if class * extends com.android.systemui.privacy.PrivacyConfig$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
-  <1> *;
-}
--if class * extends com.android.systemui.privacy.PrivacyItemController$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
-  <1> *;
-}
--if class * extends com.android.systemui.settings.UserTracker$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
-  <1> *;
-}
--if class * extends com.android.systemui.statusbar.phone.StatusBarWindowCallback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
-  <1> *;
-}
--if class * extends com.android.systemui.util.service.Observer$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
-  <1> *;
-}
--if class * extends com.android.systemui.util.service.ObservableServiceConnection$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+-if class * extends @com.android.systemui.util.annotations.WeaklyReferencedCallback **
+-keepclassmembers,allowaccessmodification @com.android.systemui.dagger.SysUISingleton class * {
   <1> *;
 }
 
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/color/qs_tile_ripple_color.xml b/packages/SystemUI/res/color/qs_tile_ripple_color.xml
new file mode 100644
index 0000000..c106254
--- /dev/null
+++ b/packages/SystemUI/res/color/qs_tile_ripple_color.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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/colorControlHighlight" android:state_hovered="true"
+        android:state_pressed="true" />
+    <!-- RippleDrawable has default way of handling hover state with highlighting but it's not
+    consistent with our approach so we make highlighting invisible and instead do custom handling
+    of hover state on a different level -->
+    <item android:color="@color/transparent" android:state_hovered="true" />
+    <item android:color="?android:attr/colorControlHighlight" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_tile_background.xml b/packages/SystemUI/res/drawable/qs_tile_background.xml
index 265f575..ef3c61b 100644
--- a/packages/SystemUI/res/drawable/qs_tile_background.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_background.xml
@@ -15,9 +15,25 @@
   ~ limitations under the License.
   -->
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
+    android:color="@color/qs_tile_ripple_color">
     <item android:id="@android:id/mask"
-        android:drawable="@drawable/qs_tile_background_shape" />
-    <item android:id="@id/background"
-        android:drawable="@drawable/qs_tile_background_shape"/>
+        android:drawable="@drawable/qs_tile_background_shape"
+        />
+    <item android:id="@id/background">
+        <layer-list>
+            <item
+                android:id="@+id/qs_tile_background_base"
+                android:drawable="@drawable/qs_tile_background_shape" />
+            <item android:id="@+id/qs_tile_background_overlay">
+                <selector>
+                    <item
+                        android:state_hovered="true"
+                        android:drawable="@drawable/qs_tile_background_shape" />
+                    <item
+                        android:state_focused="true"
+                        android:drawable="@drawable/qs_tile_background_shape" />
+                </selector>
+            </item>
+        </layer-list>
+    </item>
 </ripple>
\ No newline at end of file
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/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/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b5e4a76..6377df3 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..05f4334 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -222,12 +222,14 @@
     <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" />
     <item type="id" name="privacy_dialog_manage_app_button" />
 
     <!-- Communal mode -->
+    <item type="id" name="communal_hub" />
     <item type="id" name="communal_widget_wrapper" />
 
     <!-- Values assigned to the views in Biometrics Prompt -->
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/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/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 80040a3..631423e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -155,6 +155,26 @@
         }
     }
 
+
+    /**
+     * Requests for a new snapshot to be taken for the given task, stores it in the cache, and
+     * returns a {@link ThumbnailData} with the result.
+     */
+    @NonNull
+    public ThumbnailData takeTaskThumbnail(int taskId) {
+        TaskSnapshot snapshot = null;
+        try {
+            snapshot = getService().takeTaskSnapshot(taskId, /* updateCache= */ true);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to take task snapshot", e);
+        }
+        if (snapshot != null) {
+            return new ThumbnailData(snapshot);
+        } else {
+            return new ThumbnailData();
+        }
+    }
+
     /**
      * Removes the outdated snapshot of home task.
      *
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 eb7a735..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,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index f6a0563..9bddcd7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -22,10 +22,10 @@
 
 import com.android.app.animation.Interpolators;
 import com.android.keyguard.dagger.KeyguardStatusViewScope;
-import com.android.systemui.res.R;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.core.LogLevel;
 import com.android.systemui.plugins.ClockController;
+import com.android.systemui.res.R;
 import com.android.systemui.shared.clocks.DefaultClockController;
 
 import java.io.PrintWriter;
@@ -452,6 +452,10 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
+        // TODO: b/305022530
+        if (mClock.getConfig().getId().equals("DIGITAL_CLOCK_METRO")) {
+            mClock.getEvents().onColorPaletteChanged(mContext.getResources());
+        }
 
         if (changed) {
             post(() -> updateClockTargetRegions());
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 51c0676..3585feb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -44,8 +44,6 @@
 import android.view.WindowInsets;
 import android.view.WindowInsetsAnimationControlListener;
 import android.view.WindowInsetsAnimationController;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
@@ -66,18 +64,8 @@
  */
 public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
 
-    private final int mDisappearYTranslation;
-
-    private static final long IME_DISAPPEAR_DURATION_MS = 125;
-
-    // A delay constant to be used in a workaround for the situation where InputMethodManagerService
-    // is not switched to the new user yet.
-    // TODO: Remove this by ensuring such a race condition never happens.
-
     private TextView mPasswordEntry;
     private TextViewInputDisabler mPasswordEntryDisabler;
-    private Interpolator mLinearOutSlowInInterpolator;
-    private Interpolator mFastOutLinearInInterpolator;
     private DisappearAnimationListener mDisappearAnimationListener;
     @Nullable private MotionLayout mContainerMotionLayout;
     private boolean mAlreadyUsingSplitBouncer = false;
@@ -93,12 +81,6 @@
 
     public KeyguardPasswordView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mDisappearYTranslation = getResources().getDimensionPixelSize(
-                R.dimen.disappear_y_translation);
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
-                context, android.R.interpolator.linear_out_slow_in);
-        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(
-                context, android.R.interpolator.fast_out_linear_in);
     }
 
     /**
@@ -139,7 +121,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/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 8717a53..d2d0517 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -31,6 +31,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.WindowManager;
@@ -39,9 +40,9 @@
 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.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.res.R;
 
 public class KeyguardSimPinViewController
         extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
@@ -324,7 +325,11 @@
         } else {
             SubscriptionInfo info = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(mSubId);
             CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
-            msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
+            if (!TextUtils.isEmpty(displayName)) {
+                msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
+            } else {
+                msg = rez.getString(R.string.kg_sim_pin_instructions);
+            }
             if (info != null) {
                 color = info.getIconTint();
             }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index 248b7af..b52a36b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -29,6 +29,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.WindowManager;
 import android.widget.ImageView;
@@ -36,9 +37,9 @@
 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.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.res.R;
 
 public class KeyguardSimPukViewController
         extends KeyguardPinBasedInputViewController<KeyguardSimPukView> {
@@ -206,7 +207,11 @@
         } else {
             SubscriptionInfo info = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(mSubId);
             CharSequence displayName = info != null ? info.getDisplayName() : "";
-            msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
+            if (!TextUtils.isEmpty(displayName)) {
+                msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
+            } else {
+                msg = rez.getString(R.string.kg_puk_enter_puk_hint);
+            }
             if (info != null) {
                 color = info.getIconTint();
             }
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..b7bb35e 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;
@@ -1248,6 +1250,7 @@
      * @deprecated This is being migrated to use modern architecture, this method is visible purely
      * for bridging the gap while the migration is active.
      */
+    @Deprecated
     private void handleFaceAuthFailed() {
         Assert.isMainThread();
         String reason =
@@ -1276,6 +1279,7 @@
      * @deprecated This is being migrated to use modern architecture, this method is visible purely
      * for bridging the gap while the migration is active.
      */
+    @Deprecated
     private void handleFaceAcquired(int acquireInfo) {
         Assert.isMainThread();
         for (int i = 0; i < mCallbacks.size(); i++) {
@@ -1297,6 +1301,7 @@
      * @deprecated This is being migrated to use modern architecture, this method is visible purely
      * for bridging the gap while the migration is active.
      */
+    @Deprecated
     private void handleFaceAuthenticated(int authUserId, boolean isStrongBiometric) {
         Trace.beginSection("KeyGuardUpdateMonitor#handlerFaceAuthenticated");
         try {
@@ -1325,6 +1330,7 @@
      * @deprecated This is being migrated to use modern architecture, this method is visible purely
      * for bridging the gap while the migration is active.
      */
+    @Deprecated
     private void handleFaceHelp(int msgId, String helpString) {
         if (mFaceAcquiredInfoIgnoreList.contains(msgId)) {
             return;
@@ -1342,6 +1348,7 @@
      * @deprecated This is being migrated to use modern architecture, this method is visible purely
      * for bridging the gap while the migration is active.
      */
+    @Deprecated
     private void handleFaceError(int msgId, final String originalErrMsg) {
         Assert.isMainThread();
         String errString = originalErrMsg;
@@ -4430,6 +4437,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/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 7b59632..2476067 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -25,12 +25,14 @@
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.plugins.WeatherData;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.util.annotations.WeaklyReferencedCallback;
 
 import java.util.TimeZone;
 
 /**
  * Callback for general information relevant to lock screen.
  */
+@WeaklyReferencedCallback
 public class KeyguardUpdateMonitorCallback {
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 0d3f726..83da80f 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -692,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();
@@ -713,6 +713,23 @@
         return true;
     }
 
+    /**
+     * 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.
+     */
+    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;
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt
index c581788..1f145d8 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt
@@ -4,6 +4,7 @@
 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
@@ -23,11 +24,12 @@
     companion object {
         @Provides
         @DisplaySpecific
-        fun getDisplayContext(context: Context, display: Optional<Display>): Context {
-            return if (display.isPresent) {
-                context.createDisplayContext(display.get())
-            } else {
+        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)
             }
         }
 
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 7739021..1a34cc4 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -15,123 +15,55 @@
 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.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 dagger.Lazy;
 
-import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
@@ -154,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.
@@ -171,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.
@@ -197,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 =
@@ -211,133 +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<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;
@@ -360,183 +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(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/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/blueprints/DefaultCommunalBlueprint.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprint.kt
index 3ff1f09..d8d1dc0 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprint.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.communal.ui.view.layout.blueprints
 
+import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalHubSection
 import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalWidgetSection
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
@@ -28,10 +29,15 @@
 class DefaultCommunalBlueprint
 @Inject
 constructor(
+    defaultCommunalHubSection: DefaultCommunalHubSection,
     defaultCommunalWidgetSection: DefaultCommunalWidgetSection,
 ) : KeyguardBlueprint {
     override val id: String = COMMUNAL
-    override val sections: Set<KeyguardSection> = setOf(defaultCommunalWidgetSection)
+    override val sections: Set<KeyguardSection> =
+        setOf(
+            defaultCommunalHubSection,
+            defaultCommunalWidgetSection,
+        )
 
     companion object {
         const val COMMUNAL = "communal"
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/view/layout/sections/DefaultCommunalHubSection.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt
new file mode 100644
index 0000000..932dbfb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt
@@ -0,0 +1,57 @@
+package com.android.systemui.communal.ui.view.layout.sections
+
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.compose.ComposeFacade
+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
+
+/** A keyguard section that hosts the communal hub. */
+class DefaultCommunalHubSection @Inject constructor() : KeyguardSection() {
+    private val communalHubViewId = R.id.communal_hub
+
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        constraintLayout.addView(
+            ComposeFacade.createCommunalView(constraintLayout.context).apply {
+                id = communalHubViewId
+            },
+        )
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {}
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
+        constraintSet.apply {
+            connect(
+                communalHubViewId,
+                ConstraintSet.START,
+                ConstraintSet.PARENT_ID,
+                ConstraintSet.START,
+            )
+            connect(
+                communalHubViewId,
+                ConstraintSet.TOP,
+                ConstraintSet.PARENT_ID,
+                ConstraintSet.TOP,
+            )
+            connect(
+                communalHubViewId,
+                ConstraintSet.END,
+                ConstraintSet.PARENT_ID,
+                ConstraintSet.END,
+            )
+            connect(
+                communalHubViewId,
+                ConstraintSet.BOTTOM,
+                ConstraintSet.PARENT_ID,
+                ConstraintSet.BOTTOM,
+            )
+        }
+    }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        constraintLayout.removeView(communalHubViewId)
+    }
+}
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/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
index 1a6f7e1..5c1539a 100644
--- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
+++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
@@ -72,4 +72,9 @@
         windowInsets: StateFlow<WindowInsets?>,
         sceneByKey: Map<SceneKey, Scene>,
     ): View
+
+    /** Create a [View] that represents the communal hub. */
+    fun createCommunalView(
+        context: Context,
+    ): View
 }
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/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index ca725c0..5c38264 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -64,6 +64,7 @@
      * @deprecated Deprecdated because {@link Display#getMetrics} is deprecated.
      */
     @Provides
+    @Deprecated
     public DisplayMetrics provideDisplayMetrics(Context context) {
         DisplayMetrics displayMetrics = new DisplayMetrics();
         context.getDisplay().getMetrics(displayMetrics);
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 6bbd40c..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;
@@ -56,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
@@ -319,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) {
@@ -354,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);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index f6f24e0..11ac39f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -473,6 +473,9 @@
     // TODO(b/270437894): Tracking Bug
     val MEDIA_REMOTE_RESUME = unreleasedFlag("media_remote_resume")
 
+    // TODO(b/304506662): Tracking Bug
+    val MEDIA_DEVICE_NAME_FIX = unreleasedFlag("media_device_name_fix", teamfood = true)
+
     // 1000 - dock
     val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag("simulate_dock_through_charging")
 
@@ -667,8 +670,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")
@@ -786,8 +787,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/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index fde92b8..0bac40b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -451,7 +451,8 @@
         if (!keyguardStateController.isKeyguardGoingAway &&
                 willUnlockWithInWindowLauncherAnimations) {
             try {
-                launcherUnlockController?.setUnlockAmount(1f, true /* forceIfAnimating */)
+                launcherUnlockController?.setUnlockAmount(1f,
+                        biometricUnlockControllerLazy.get().isWakeAndUnlock /* forceIfAnimating */)
             } catch (e: DeadObjectException) {
                 Log.e(TAG, "launcherUnlockAnimationController was dead, but non-null in " +
                         "onKeyguardGoingAwayChanged(). Catching exception as this should mean " +
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 41bde91..081edd1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -39,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;
@@ -96,6 +97,7 @@
         KeyguardUserSwitcherComponent.class},
         includes = {
             CommunalRepositoryModule.class,
+            CommunalTutorialRepositoryModule.class,
             CommunalWidgetRepositoryModule.class,
             FalsingModule.class,
             KeyguardDataQuickAffordanceModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 75aa4b60f..ca882e5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -29,9 +29,7 @@
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 
 @SysUISingleton
@@ -64,29 +62,14 @@
 
     private fun listenForDreamingToOccluded() {
         scope.launch {
-            keyguardInteractor.isDreaming
-                // Add a slight delay, as dreaming and occluded events will arrive with a small gap
-                // in time. This prevents a transition to OCCLUSION happening prematurely.
-                .onEach { delay(50) }
-                .sample(
-                    combine(
-                        keyguardInteractor.isKeyguardOccluded,
-                        transitionInteractor.startedKeyguardTransitionStep,
-                        ::Pair,
-                    ),
-                    ::toTriple
-                )
-                .collect { (isDreaming, isOccluded, lastStartedTransition) ->
+            combine(keyguardInteractor.isKeyguardOccluded, keyguardInteractor.isDreaming, ::Pair)
+                .sample(transitionInteractor.startedKeyguardTransitionStep, ::toTriple)
+                .collect { (isOccluded, isDreaming, lastStartedTransition) ->
                     if (
                         isOccluded &&
                             !isDreaming &&
-                            (lastStartedTransition.to == KeyguardState.DREAMING ||
-                                lastStartedTransition.to == KeyguardState.LOCKSCREEN)
+                            lastStartedTransition.to == KeyguardState.DREAMING
                     ) {
-                        // At the moment, checking for LOCKSCREEN state above provides a corrective
-                        // action. There's no great signal to determine when the dream is ending
-                        // and a transition to OCCLUDED is beginning directly. For now, the solution
-                        // is DREAMING->LOCKSCREEN->OCCLUDED
                         startTransitionTo(KeyguardState.OCCLUDED)
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index ffa1a49..660bd84 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -318,16 +318,9 @@
     private fun listenForLockscreenToOccluded() {
         scope.launch {
             keyguardInteractor.isKeyguardOccluded
-                .sample(
-                    combine(
-                        transitionInteractor.startedKeyguardState,
-                        keyguardInteractor.isDreaming,
-                        ::Pair
-                    ),
-                    ::toTriple
-                )
-                .collect { (isOccluded, keyguardState, isDreaming) ->
-                    if (isOccluded && !isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
+                .sample(transitionInteractor.startedKeyguardState, ::Pair)
+                .collect { (isOccluded, keyguardState) ->
+                    if (isOccluded && keyguardState == KeyguardState.LOCKSCREEN) {
                         startTransitionTo(KeyguardState.OCCLUDED)
                     }
                 }
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/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 f0d118c..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
@@ -240,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 c6d8ec7..4a2954d 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
@@ -29,12 +29,12 @@
 import android.os.IBinder
 import android.view.Display
 import android.view.Display.DEFAULT_DISPLAY
+import android.view.DisplayInfo
 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
@@ -129,7 +129,7 @@
         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 val display: Display? = displayManager.getDisplay(displayId)
 
     private var host: SurfaceControlViewHost
 
@@ -179,7 +179,7 @@
 
     fun render() {
         mainHandler.post {
-            val previewContext = context.createDisplayContext(display)
+            val previewContext = display?.let { context.createDisplayContext(it) } ?: context
 
             val rootView = FrameLayout(previewContext)
 
@@ -189,16 +189,18 @@
                 setUpBottomArea(rootView)
             }
 
-            val windowContext = context.createWindowContext(display, TYPE_KEYGUARD, null)
-            val windowManagerOfDisplay = windowContext.getSystemService(WindowManager::class.java)
+            var displayInfo: DisplayInfo? = null
+            display?.let {
+                displayInfo = DisplayInfo()
+                it.getDisplayInfo(displayInfo)
+            }
             rootView.measure(
                 View.MeasureSpec.makeMeasureSpec(
-                    windowManagerOfDisplay?.currentWindowMetrics?.bounds?.width()
-                        ?: windowManager.currentWindowMetrics.bounds.width(),
+                    displayInfo?.logicalWidth ?: windowManager.currentWindowMetrics.bounds.width(),
                     View.MeasureSpec.EXACTLY
                 ),
                 View.MeasureSpec.makeMeasureSpec(
-                    windowManagerOfDisplay?.currentWindowMetrics?.bounds?.height()
+                    displayInfo?.logicalHeight
                         ?: windowManager.currentWindowMetrics.bounds.height(),
                     View.MeasureSpec.EXACTLY
                 ),
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/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/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 80be766..7a48836 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -285,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.");
@@ -293,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/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
index a1291a4..724241d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.os.SystemProperties
 import android.util.Log
+import com.android.internal.annotations.KeepForWeakReference
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.broadcast.BroadcastSender
 import com.android.systemui.dagger.qualifiers.Main
@@ -82,6 +83,8 @@
     private var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
     private var reactivatedKey: String? = null
 
+    // Ensure the field (and associated reference) isn't removed during optimization.
+    @KeepForWeakReference
     private val userTrackerCallback =
         object : UserTracker.Callback {
             override fun onUserChanged(newUser: Int, userContext: Context) {
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/media/controls/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
index 1fe93ed..1db31ae 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
@@ -21,6 +21,7 @@
 import android.content.Context
 import android.graphics.drawable.Drawable
 import android.media.MediaRouter2Manager
+import android.media.RoutingSessionInfo
 import android.media.session.MediaController
 import android.text.TextUtils
 import android.util.Log
@@ -31,17 +32,20 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.settingslib.media.LocalMediaManager
 import com.android.settingslib.media.MediaDevice
+import com.android.settingslib.media.PhoneMediaDevice
 import com.android.systemui.Dumpable
-import com.android.systemui.res.R
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
 import com.android.systemui.media.controls.models.player.MediaData
 import com.android.systemui.media.controls.models.player.MediaDeviceData
 import com.android.systemui.media.controls.util.MediaControllerFactory
 import com.android.systemui.media.controls.util.MediaDataUtils
 import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager
 import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManagerFactory
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.policy.ConfigurationController
 import java.io.PrintWriter
 import java.util.concurrent.Executor
@@ -64,7 +68,8 @@
     private val localBluetoothManager: LocalBluetoothManager?,
     @Main private val fgExecutor: Executor,
     @Background private val bgExecutor: Executor,
-    dumpManager: DumpManager
+    dumpManager: DumpManager,
+    private val featureFlags: FeatureFlagsClassic,
 ) : MediaDataManager.Listener, Dumpable {
 
     private val listeners: MutableSet<Listener> = mutableSetOf()
@@ -215,6 +220,7 @@
                 println("    volumeControlId=$volumeControlId cached= $playbackVolumeControlId")
                 println("    routingSession=$routingSession")
                 println("    selectedRoutes=$selectedRoutes")
+                println("    currentConnectedDevice=${localMediaManager.currentConnectedDevice}")
             }
         }
 
@@ -348,16 +354,16 @@
                 }
                 val device =
                     aboutToConnect?.fullMediaDevice ?: localMediaManager.currentConnectedDevice
-                val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
+                val routingSession =
+                    controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
 
                 // If we have a controller but get a null route, then don't trust the device
-                val enabled = device != null && (controller == null || route != null)
-                val name =
-                    if (controller == null || route != null) {
-                        route?.name?.toString() ?: device?.name
-                    } else {
-                        null
-                    }
+                val enabled = device != null && (controller == null || routingSession != null)
+
+                val name = getDeviceName(device, routingSession)
+                if (DEBUG) {
+                    Log.d(TAG, "new device name $name")
+                }
                 current =
                     MediaDeviceData(
                         enabled,
@@ -369,6 +375,57 @@
             }
         }
 
+        /** Return a display name for the current device / route, or null if not possible */
+        private fun getDeviceName(
+            device: MediaDevice?,
+            routingSession: RoutingSessionInfo?,
+        ): String? {
+            val selectedRoutes = routingSession?.let { mr2manager.getSelectedRoutes(it) }
+
+            if (DEBUG) {
+                Log.d(
+                    TAG,
+                    "device is $device, controller $controller," +
+                        " routingSession ${routingSession?.name}" +
+                        " or ${selectedRoutes?.firstOrNull()?.name}"
+                )
+            }
+
+            if (!featureFlags.isEnabled(Flags.MEDIA_DEVICE_NAME_FIX)) {
+                if (controller == null || routingSession != null) {
+                    return routingSession?.name?.toString() ?: device?.name
+                }
+                return null
+            }
+
+            if (controller == null) {
+                // In resume state, we don't have a controller - just use the device name
+                return device?.name
+            }
+
+            if (routingSession == null) {
+                // This happens when casting from apps that do not support MediaRouter2
+                // The output switcher can't show anything useful here, so set to null
+                return null
+            }
+
+            // If this is a user route (app / cast provided), use the provided name
+            if (!routingSession.isSystemSession) {
+                return routingSession.name?.toString() ?: device?.name
+            }
+
+            selectedRoutes?.firstOrNull()?.let {
+                if (device is PhoneMediaDevice) {
+                    // Get the (localized) name for this phone device
+                    return PhoneMediaDevice.getSystemRouteNameFromType(context, it)
+                } else {
+                    // If it's another type of device (in practice, Bluetooth), use the route name
+                    return it.name.toString()
+                }
+            }
+            return null
+        }
+
         private fun isLeAudioBroadcastEnabled(): Boolean {
             if (localBluetoothManager != null) {
                 val profileManager = localBluetoothManager.profileManager
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/MediaProjectionAppSelectorController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
index e61650f..fced117 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
@@ -20,10 +20,15 @@
 import android.os.UserHandle
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
+import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver
+import com.android.systemui.shared.recents.model.ThumbnailData
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
 import kotlinx.coroutines.cancel
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
 
 @MediaProjectionAppSelectorScope
@@ -36,7 +41,8 @@
     @HostUserHandle private val hostUserHandle: UserHandle,
     @MediaProjectionAppSelector private val scope: CoroutineScope,
     @MediaProjectionAppSelector private val appSelectorComponentName: ComponentName,
-    @MediaProjectionAppSelector private val callerPackageName: String?
+    @MediaProjectionAppSelector private val callerPackageName: String?,
+    private val thumbnailLoader: RecentTaskThumbnailLoader,
 ) {
 
     fun init() {
@@ -46,6 +52,11 @@
             val tasks =
                 recentTasks.filterDevicePolicyRestrictedTasks().filterAppSelector().sortedTasks()
 
+            // Thumbnails are not fresh for the foreground task(s). They are only refreshed at
+            // launch, going to home, or going to overview.
+            // For this reason, we need to refresh them here.
+            refreshForegroundTaskThumbnails(tasks)
+
             view.bind(tasks)
         }
     }
@@ -54,6 +65,16 @@
         scope.cancel()
     }
 
+    private suspend fun refreshForegroundTaskThumbnails(tasks: List<RecentTask>) {
+        coroutineScope {
+            val thumbnails: List<Deferred<ThumbnailData?>> =
+                tasks
+                    .filter { it.isForegroundTask }
+                    .map { async { thumbnailLoader.captureThumbnail(it.taskId) } }
+            thumbnails.forEach { thumbnail -> thumbnail.await() }
+        }
+    }
+
     /** Removes all recent tasks that should be blocked according to the policy */
     private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> = filter {
         devicePolicyResolver.isScreenCaptureAllowed(
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
index 41e2286..a9e6c53 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
@@ -25,5 +25,6 @@
     @UserIdInt val userId: Int,
     val topActivityComponent: ComponentName?,
     val baseIntentComponent: ComponentName?,
-    @ColorInt val colorBackground: Int?
+    @ColorInt val colorBackground: Int?,
+    val isForegroundTask: Boolean,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
index 01398cf..aa4c4e5 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
@@ -48,9 +48,14 @@
 
     override suspend fun loadRecentTasks(): List<RecentTask> =
         withContext(coroutineDispatcher) {
-            val rawRecentTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList()
-
-            rawRecentTasks
+            val groupedTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList()
+            // Note: the returned task list is from the most-recent to least-recent order.
+            // The last foreground task is at index 1, because at index 0 will be our app selector.
+            val foregroundGroup = groupedTasks.elementAtOrNull(1)
+            val foregroundTaskId1 = foregroundGroup?.taskInfo1?.taskId
+            val foregroundTaskId2 = foregroundGroup?.taskInfo2?.taskId
+            val foregroundTaskIds = listOfNotNull(foregroundTaskId1, foregroundTaskId2)
+            groupedTasks
                 .flatMap { listOfNotNull(it.taskInfo1, it.taskInfo2) }
                 .map {
                     RecentTask(
@@ -58,7 +63,8 @@
                         it.userId,
                         it.topActivity,
                         it.baseIntent?.component,
-                        it.taskDescription?.backgroundColor
+                        it.taskDescription?.backgroundColor,
+                        isForegroundTask = it.taskId in foregroundTaskIds
                     )
                 }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt
index 47faaed..ccf272c 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt
@@ -25,6 +25,8 @@
 
 interface RecentTaskThumbnailLoader {
     suspend fun loadThumbnail(taskId: Int): ThumbnailData?
+
+    suspend fun captureThumbnail(taskId: Int): ThumbnailData?
 }
 
 class ActivityTaskManagerThumbnailLoader
@@ -36,8 +38,13 @@
 
     override suspend fun loadThumbnail(taskId: Int): ThumbnailData? =
         withContext(coroutineDispatcher) {
-            val thumbnailData =
-                activityManager.getTaskThumbnail(taskId, /* isLowResolution= */ false)
-            if (thumbnailData.thumbnail == null) null else thumbnailData
+            activityManager.getTaskThumbnail(taskId, /* isLowResolution= */ false).takeIf {
+                it.thumbnail != null
+            }
+        }
+
+    override suspend fun captureThumbnail(taskId: Int): ThumbnailData? =
+        withContext(coroutineDispatcher) {
+            activityManager.takeTaskThumbnail(taskId).takeIf { it.thumbnail != null }
         }
 }
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/people/ui/view/PeopleViewBinder.kt b/packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt
index c567d56..10a2b3c 100644
--- a/packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt
@@ -31,10 +31,10 @@
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.res.R
 import com.android.systemui.people.PeopleSpaceTileView
 import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
 import com.android.systemui.people.ui.viewmodel.PeopleViewModel
+import com.android.systemui.res.R
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.launch
@@ -101,10 +101,10 @@
                                 view,
                                 priorityTiles,
                                 recentTiles,
-                                viewModel::onTileClicked,
+                                viewModel.onTileClicked,
                             )
                         } else {
-                            setNoConversationsContent(view, viewModel::onUserJourneyCancelled)
+                            setNoConversationsContent(view, viewModel.onUserJourneyCancelled)
                         }
                     }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/people/ui/viewmodel/PeopleViewModel.kt b/packages/SystemUI/src/com/android/systemui/people/ui/viewmodel/PeopleViewModel.kt
index ed7c21b..b847e95 100644
--- a/packages/SystemUI/src/com/android/systemui/people/ui/viewmodel/PeopleViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/people/ui/viewmodel/PeopleViewModel.kt
@@ -23,35 +23,32 @@
 import android.util.Log
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
-import com.android.systemui.res.R
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.people.PeopleSpaceUtils
 import com.android.systemui.people.PeopleTileViewHelper
 import com.android.systemui.people.data.model.PeopleTileModel
 import com.android.systemui.people.data.repository.PeopleTileRepository
 import com.android.systemui.people.data.repository.PeopleWidgetRepository
+import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 
+private const val TAG = "PeopleViewModel"
+
 /**
  * Models UI state for the people space, allowing the user to select which conversation should be
  * associated to a new or existing Conversation widget.
  */
 class PeopleViewModel(
-    @Application private val context: Context,
-    private val tileRepository: PeopleTileRepository,
-    private val widgetRepository: PeopleWidgetRepository,
-) : ViewModel() {
     /**
      * The list of the priority tiles/conversations.
      *
      * Important: Even though this is a Flow, the underlying API used to populate this Flow is not
      * reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles.
      */
-    private val _priorityTiles = MutableStateFlow(priorityTiles())
-    val priorityTiles: StateFlow<List<PeopleTileViewModel>> = _priorityTiles.asStateFlow()
+    val priorityTiles: StateFlow<List<PeopleTileViewModel>>,
 
     /**
      * The list of the priority tiles/conversations.
@@ -59,84 +56,29 @@
      * Important: Even though this is a Flow, the underlying API used to populate this Flow is not
      * reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles.
      */
-    private val _recentTiles = MutableStateFlow(recentTiles())
-    val recentTiles: StateFlow<List<PeopleTileViewModel>> = _recentTiles.asStateFlow()
+    val recentTiles: StateFlow<List<PeopleTileViewModel>>,
 
     /** The ID of the widget currently being edited/added. */
-    private val _appWidgetId = MutableStateFlow(INVALID_APPWIDGET_ID)
-    val appWidgetId: StateFlow<Int> = _appWidgetId.asStateFlow()
+    val appWidgetId: StateFlow<Int>,
 
     /** The result of this user journey. */
-    private val _result = MutableStateFlow<Result?>(null)
-    val result: StateFlow<Result?> = _result.asStateFlow()
+    val result: StateFlow<Result?>,
 
     /** Refresh the [priorityTiles] and [recentTiles]. */
-    fun onTileRefreshRequested() {
-        _priorityTiles.value = priorityTiles()
-        _recentTiles.value = recentTiles()
-    }
+    val onTileRefreshRequested: () -> Unit,
 
     /** Called when the [appWidgetId] should be changed to [widgetId]. */
-    fun onWidgetIdChanged(widgetId: Int) {
-        _appWidgetId.value = widgetId
-    }
+    val onWidgetIdChanged: (widgetId: Int) -> Unit,
 
     /** Clear [result], setting it to null. */
-    fun clearResult() {
-        _result.value = null
-    }
+    val clearResult: () -> Unit,
 
     /** Called when a tile is clicked. */
-    fun onTileClicked(tile: PeopleTileViewModel) {
-        val widgetId = _appWidgetId.value
-        if (PeopleSpaceUtils.DEBUG) {
-            Log.d(
-                TAG,
-                "Put ${tile.username}'s shortcut ID: ${tile.key.shortcutId} for widget ID $widgetId"
-            )
-        }
-        widgetRepository.setWidgetTile(widgetId, tile.key)
-        _result.value =
-            Result.Success(Intent().apply { putExtra(EXTRA_APPWIDGET_ID, appWidgetId.value) })
-    }
+    val onTileClicked: (tile: PeopleTileViewModel) -> Unit,
 
     /** Called when this user journey is cancelled. */
-    fun onUserJourneyCancelled() {
-        _result.value = Result.Cancelled
-    }
-
-    private fun priorityTiles(): List<PeopleTileViewModel> {
-        return try {
-            tileRepository.priorityTiles().map { it.toViewModel() }
-        } catch (e: Exception) {
-            Log.e(TAG, "Couldn't retrieve priority conversations", e)
-            emptyList()
-        }
-    }
-
-    private fun recentTiles(): List<PeopleTileViewModel> {
-        return try {
-            tileRepository.recentTiles().map { it.toViewModel() }
-        } catch (e: Exception) {
-            Log.e(TAG, "Couldn't retrieve recent conversations", e)
-            emptyList()
-        }
-    }
-
-    private fun PeopleTileModel.toViewModel(): PeopleTileViewModel {
-        val icon =
-            PeopleTileViewHelper.getPersonIconBitmap(
-                context,
-                this,
-                PeopleTileViewHelper.getSizeInDp(
-                    context,
-                    R.dimen.avatar_size_for_medium,
-                    context.resources.displayMetrics.density,
-                )
-            )
-        return PeopleTileViewModel(key, icon, username)
-    }
-
+    val onUserJourneyCancelled: () -> Unit,
+) : ViewModel() {
     /** The Factory that should be used to create a [PeopleViewModel]. */
     class Factory
     @Inject
@@ -153,10 +95,94 @@
 
     sealed class Result {
         class Success(val data: Intent) : Result()
+
         object Cancelled : Result()
     }
+}
 
-    companion object {
-        private const val TAG = "PeopleViewModel"
+private fun PeopleViewModel(
+    @Application context: Context,
+    tileRepository: PeopleTileRepository,
+    widgetRepository: PeopleWidgetRepository,
+): PeopleViewModel {
+    fun priorityTiles(): List<PeopleTileViewModel> {
+        return try {
+            tileRepository.priorityTiles().map { it.toViewModel(context) }
+        } catch (e: Exception) {
+            Log.e(TAG, "Couldn't retrieve priority conversations", e)
+            emptyList()
+        }
     }
+
+    fun recentTiles(): List<PeopleTileViewModel> {
+        return try {
+            tileRepository.recentTiles().map { it.toViewModel(context) }
+        } catch (e: Exception) {
+            Log.e(TAG, "Couldn't retrieve recent conversations", e)
+            emptyList()
+        }
+    }
+
+    val priorityTiles = MutableStateFlow(priorityTiles())
+    val recentTiles = MutableStateFlow(recentTiles())
+    val appWidgetId = MutableStateFlow(INVALID_APPWIDGET_ID)
+    val result = MutableStateFlow<PeopleViewModel.Result?>(null)
+
+    fun onTileRefreshRequested() {
+        priorityTiles.value = priorityTiles()
+        recentTiles.value = recentTiles()
+    }
+
+    fun onWidgetIdChanged(widgetId: Int) {
+        appWidgetId.value = widgetId
+    }
+
+    fun clearResult() {
+        result.value = null
+    }
+
+    fun onTileClicked(tile: PeopleTileViewModel) {
+        val widgetId = appWidgetId.value
+        if (PeopleSpaceUtils.DEBUG) {
+            Log.d(
+                TAG,
+                "Put ${tile.username}'s shortcut ID: ${tile.key.shortcutId} for widget ID $widgetId"
+            )
+        }
+        widgetRepository.setWidgetTile(widgetId, tile.key)
+        result.value =
+            PeopleViewModel.Result.Success(
+                Intent().apply { putExtra(EXTRA_APPWIDGET_ID, appWidgetId.value) }
+            )
+    }
+
+    fun onUserJourneyCancelled() {
+        result.value = PeopleViewModel.Result.Cancelled
+    }
+
+    return PeopleViewModel(
+        priorityTiles = priorityTiles.asStateFlow(),
+        recentTiles = recentTiles.asStateFlow(),
+        appWidgetId = appWidgetId.asStateFlow(),
+        result = result.asStateFlow(),
+        onTileRefreshRequested = ::onTileRefreshRequested,
+        onWidgetIdChanged = ::onWidgetIdChanged,
+        clearResult = ::clearResult,
+        onTileClicked = ::onTileClicked,
+        onUserJourneyCancelled = ::onUserJourneyCancelled,
+    )
+}
+
+fun PeopleTileModel.toViewModel(@Application context: Context): PeopleTileViewModel {
+    val icon =
+        PeopleTileViewHelper.getPersonIconBitmap(
+            context,
+            this,
+            PeopleTileViewHelper.getSizeInDp(
+                context,
+                R.dimen.avatar_size_for_medium,
+                context.resources.displayMetrics.density,
+            )
+        )
+    return PeopleTileViewModel(key, icon, username)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt
index d949a2a..67d390d 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.util.DeviceConfigProxy
 import com.android.systemui.util.asIndenting
+import com.android.systemui.util.annotations.WeaklyReferencedCallback
 import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.withIncreasedIndent
 import java.io.PrintWriter
@@ -144,6 +145,7 @@
         ipw.flush()
     }
 
+    @WeaklyReferencedCallback
     interface Callback {
         fun onFlagMicCameraChanged(flag: Boolean) {}
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index 202254b..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;
@@ -934,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/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/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 acee8e9..c3744df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -81,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;
 
@@ -96,6 +97,7 @@
             CommandQueue commandQueue,
             StatusBarIconController statusBarIconController,
             PanelInteractor panelInteractor,
+            TileLifecycleManager.Factory tileLifecycleManagerFactory,
             CustomTileAddedRepository customTileAddedRepository,
             @Background DelayableExecutor backgroundExecutor) {
         mHost = host;
@@ -109,6 +111,7 @@
         mStatusBarIconController = statusBarIconController;
         mCommandQueue.addCallback(mRequestListeningCallback);
         mPanelInteractor = panelInteractor;
+        mTileLifecycleManagerFactory = tileLifecycleManagerFactory;
         mCustomTileAddedRepository = customTileAddedRepository;
         mBackgroundExecutor = backgroundExecutor;
     }
@@ -137,8 +140,8 @@
 
     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(CustomTileInterface tile, TileServiceManager service) {
@@ -323,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() {
@@ -356,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();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 64fa33c..eff3e76 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED
 import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
 import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
+import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
 import com.android.systemui.res.R
 import com.android.systemui.util.icuMessageFormat
 import javax.inject.Inject
@@ -47,17 +48,35 @@
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 
+private const val TAG = "FooterActionsViewModel"
+
 /** A ViewModel for the footer actions. */
 class FooterActionsViewModel(
-    @Application appContext: Context,
-    private val footerActionsInteractor: FooterActionsInteractor,
-    private val falsingManager: FalsingManager,
-    private val globalActionsDialogLite: GlobalActionsDialogLite,
-    showPowerButton: Boolean,
-) {
-    /** The context themed with the Quick Settings colors. */
-    private val context = ContextThemeWrapper(appContext, R.style.Theme_SystemUI_QuickSettings)
+    /** The model for the security button. */
+    val security: Flow<FooterActionsSecurityButtonViewModel?>,
 
+    /** The model for the foreground services button. */
+    val foregroundServices: Flow<FooterActionsForegroundServicesButtonViewModel?>,
+
+    /** The model for the user switcher button. */
+    val userSwitcher: Flow<FooterActionsButtonViewModel?>,
+
+    /** The model for the settings button. */
+    val settings: FooterActionsButtonViewModel,
+
+    /** The model for the power button. */
+    val power: FooterActionsButtonViewModel?,
+
+    /**
+     * Observe the device monitoring dialog requests and show the dialog accordingly. This function
+     * will suspend indefinitely and will need to be cancelled to stop observing.
+     *
+     * Important: [quickSettingsContext] must be the [Context] associated to the
+     * [Quick Settings fragment][com.android.systemui.qs.QSFragmentLegacy], and the call to this
+     * function must be cancelled when that fragment is destroyed.
+     */
+    val observeDeviceMonitoringDialogRequests: suspend (quickSettingsContext: Context) -> Unit,
+) {
     /**
      * Whether the UI rendering this ViewModel should be visible. Note that even when this is false,
      * the UI should still participate to the layout it is included in (i.e. in the View world it
@@ -74,107 +93,6 @@
     private val _backgroundAlpha = MutableStateFlow(1f)
     val backgroundAlpha: StateFlow<Float> = _backgroundAlpha.asStateFlow()
 
-    /** The model for the security button. */
-    val security: Flow<FooterActionsSecurityButtonViewModel?> =
-        footerActionsInteractor.securityButtonConfig
-            .map { config ->
-                val (icon, text, isClickable) = config ?: return@map null
-                FooterActionsSecurityButtonViewModel(
-                    icon,
-                    text,
-                    if (isClickable) this::onSecurityButtonClicked else null,
-                )
-            }
-            .distinctUntilChanged()
-
-    /** The model for the foreground services button. */
-    val foregroundServices: Flow<FooterActionsForegroundServicesButtonViewModel?> =
-        combine(
-                footerActionsInteractor.foregroundServicesCount,
-                footerActionsInteractor.hasNewForegroundServices,
-                security,
-            ) { foregroundServicesCount, hasNewChanges, securityModel ->
-                if (foregroundServicesCount <= 0) {
-                    return@combine null
-                }
-
-                val text =
-                    icuMessageFormat(
-                        context.resources,
-                        R.string.fgs_manager_footer_label,
-                        foregroundServicesCount,
-                    )
-                FooterActionsForegroundServicesButtonViewModel(
-                    foregroundServicesCount,
-                    text = text,
-                    displayText = securityModel == null,
-                    hasNewChanges = hasNewChanges,
-                    this::onForegroundServiceButtonClicked,
-                )
-            }
-            .distinctUntilChanged()
-
-    /** The model for the user switcher button. */
-    val userSwitcher: Flow<FooterActionsButtonViewModel?> =
-        footerActionsInteractor.userSwitcherStatus
-            .map { userSwitcherStatus ->
-                when (userSwitcherStatus) {
-                    UserSwitcherStatusModel.Disabled -> null
-                    is UserSwitcherStatusModel.Enabled -> {
-                        if (userSwitcherStatus.currentUserImage == null) {
-                            Log.e(
-                                TAG,
-                                "Skipped the addition of user switcher button because " +
-                                    "currentUserImage is missing",
-                            )
-                            return@map null
-                        }
-
-                        userSwitcherButton(userSwitcherStatus)
-                    }
-                }
-            }
-            .distinctUntilChanged()
-
-    /** The model for the settings button. */
-    val settings: FooterActionsButtonViewModel =
-        FooterActionsButtonViewModel(
-            id = R.id.settings_button_container,
-            Icon.Resource(
-                R.drawable.ic_settings,
-                ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
-            ),
-            iconTint =
-                Utils.getColorAttrDefaultColor(
-                    context,
-                    R.attr.onShadeInactiveVariant,
-                ),
-            backgroundColor = R.attr.shadeInactive,
-            this::onSettingsButtonClicked,
-        )
-
-    /** The model for the power button. */
-    val power: FooterActionsButtonViewModel? =
-        if (showPowerButton) {
-            FooterActionsButtonViewModel(
-                id = R.id.pm_lite,
-                Icon.Resource(
-                    android.R.drawable.ic_lock_power_off,
-                    ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
-                ),
-                iconTint =
-                    Utils.getColorAttrDefaultColor(
-                        context,
-                        R.attr.onShadeActive,
-                    ),
-                backgroundColor = R.attr.shadeActive,
-                this::onPowerButtonClicked,
-            )
-        } else {
-            null
-        }
-
-    /** Called when the visibility of the UI rendering this model should be changed. */
     fun onVisibilityChangeRequested(visible: Boolean) {
         _isVisible.value = visible
     }
@@ -195,89 +113,6 @@
         }
     }
 
-    /**
-     * Observe the device monitoring dialog requests and show the dialog accordingly. This function
-     * will suspend indefinitely and will need to be cancelled to stop observing.
-     *
-     * Important: [quickSettingsContext] must be the [Context] associated to the
-     * [Quick Settings fragment][com.android.systemui.qs.QSFragmentLegacy], and the call to this
-     * function must be cancelled when that fragment is destroyed.
-     */
-    suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) {
-        footerActionsInteractor.deviceMonitoringDialogRequests.collect {
-            footerActionsInteractor.showDeviceMonitoringDialog(
-                quickSettingsContext,
-                expandable = null,
-            )
-        }
-    }
-
-    private fun onSecurityButtonClicked(quickSettingsContext: Context, expandable: Expandable) {
-        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return
-        }
-
-        footerActionsInteractor.showDeviceMonitoringDialog(quickSettingsContext, expandable)
-    }
-
-    private fun onForegroundServiceButtonClicked(expandable: Expandable) {
-        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return
-        }
-
-        footerActionsInteractor.showForegroundServicesDialog(expandable)
-    }
-
-    private fun onUserSwitcherClicked(expandable: Expandable) {
-        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return
-        }
-
-        footerActionsInteractor.showUserSwitcher(expandable)
-    }
-
-    private fun onSettingsButtonClicked(expandable: Expandable) {
-        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return
-        }
-
-        footerActionsInteractor.showSettings(expandable)
-    }
-
-    private fun onPowerButtonClicked(expandable: Expandable) {
-        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return
-        }
-
-        footerActionsInteractor.showPowerMenuDialog(globalActionsDialogLite, expandable)
-    }
-
-    private fun userSwitcherButton(
-        status: UserSwitcherStatusModel.Enabled
-    ): FooterActionsButtonViewModel {
-        val icon = status.currentUserImage!!
-
-        return FooterActionsButtonViewModel(
-            id = R.id.multi_user_switch,
-            icon =
-                Icon.Loaded(
-                    icon,
-                    ContentDescription.Loaded(
-                        userSwitcherContentDescription(status.currentUserName)
-                    ),
-                ),
-            iconTint = null,
-            backgroundColor = R.attr.shadeInactive,
-            onClick = this::onUserSwitcherClicked,
-        )
-    }
-
-    private fun userSwitcherContentDescription(currentUser: String?): String? {
-        return currentUser?.let { user ->
-            context.getString(R.string.accessibility_quick_settings_user, user)
-        }
-    }
-
     @SysUISingleton
     class Factory
     @Inject
@@ -315,8 +150,237 @@
             )
         }
     }
+}
 
-    companion object {
-        private const val TAG = "FooterActionsViewModel"
+fun FooterActionsViewModel(
+    @Application appContext: Context,
+    footerActionsInteractor: FooterActionsInteractor,
+    falsingManager: FalsingManager,
+    globalActionsDialogLite: GlobalActionsDialogLite,
+    showPowerButton: Boolean,
+): FooterActionsViewModel {
+    suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) {
+        footerActionsInteractor.deviceMonitoringDialogRequests.collect {
+            footerActionsInteractor.showDeviceMonitoringDialog(
+                quickSettingsContext,
+                expandable = null,
+            )
+        }
     }
+
+    fun onSecurityButtonClicked(quickSettingsContext: Context, expandable: Expandable) {
+        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+            return
+        }
+
+        footerActionsInteractor.showDeviceMonitoringDialog(quickSettingsContext, expandable)
+    }
+
+    fun onForegroundServiceButtonClicked(expandable: Expandable) {
+        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+            return
+        }
+
+        footerActionsInteractor.showForegroundServicesDialog(expandable)
+    }
+
+    fun onUserSwitcherClicked(expandable: Expandable) {
+        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+            return
+        }
+
+        footerActionsInteractor.showUserSwitcher(expandable)
+    }
+
+    fun onSettingsButtonClicked(expandable: Expandable) {
+        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+            return
+        }
+
+        footerActionsInteractor.showSettings(expandable)
+    }
+
+    fun onPowerButtonClicked(expandable: Expandable) {
+        if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+            return
+        }
+
+        footerActionsInteractor.showPowerMenuDialog(globalActionsDialogLite, expandable)
+    }
+
+    val qsThemedContext = ContextThemeWrapper(appContext, R.style.Theme_SystemUI_QuickSettings)
+
+    val security =
+        footerActionsInteractor.securityButtonConfig
+            .map { config ->
+                config?.let { securityButtonViewModel(it, ::onSecurityButtonClicked) }
+            }
+            .distinctUntilChanged()
+
+    val foregroundServices =
+        combine(
+                footerActionsInteractor.foregroundServicesCount,
+                footerActionsInteractor.hasNewForegroundServices,
+                security,
+            ) { foregroundServicesCount, hasNewChanges, securityModel ->
+                if (foregroundServicesCount <= 0) {
+                    return@combine null
+                }
+
+                foregroundServicesButtonViewModel(
+                    qsThemedContext,
+                    foregroundServicesCount,
+                    securityModel,
+                    hasNewChanges,
+                    ::onForegroundServiceButtonClicked,
+                )
+            }
+            .distinctUntilChanged()
+
+    val userSwitcher =
+        footerActionsInteractor.userSwitcherStatus
+            .map { userSwitcherStatus ->
+                when (userSwitcherStatus) {
+                    UserSwitcherStatusModel.Disabled -> null
+                    is UserSwitcherStatusModel.Enabled -> {
+                        if (userSwitcherStatus.currentUserImage == null) {
+                            Log.e(
+                                TAG,
+                                "Skipped the addition of user switcher button because " +
+                                    "currentUserImage is missing",
+                            )
+                            return@map null
+                        }
+
+                        userSwitcherButtonViewModel(
+                            qsThemedContext,
+                            userSwitcherStatus,
+                            ::onUserSwitcherClicked
+                        )
+                    }
+                }
+            }
+            .distinctUntilChanged()
+
+    val settings = settingsButtonViewModel(qsThemedContext, ::onSettingsButtonClicked)
+    val power =
+        if (showPowerButton) {
+            powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked)
+        } else {
+            null
+        }
+
+    return FooterActionsViewModel(
+        security = security,
+        foregroundServices = foregroundServices,
+        userSwitcher = userSwitcher,
+        settings = settings,
+        power = power,
+        observeDeviceMonitoringDialogRequests = ::observeDeviceMonitoringDialogRequests,
+    )
+}
+
+fun securityButtonViewModel(
+    config: SecurityButtonConfig,
+    onSecurityButtonClicked: (Context, Expandable) -> Unit,
+): FooterActionsSecurityButtonViewModel {
+    val (icon, text, isClickable) = config
+    return FooterActionsSecurityButtonViewModel(
+        icon,
+        text,
+        if (isClickable) onSecurityButtonClicked else null,
+    )
+}
+
+fun foregroundServicesButtonViewModel(
+    qsThemedContext: Context,
+    foregroundServicesCount: Int,
+    securityModel: FooterActionsSecurityButtonViewModel?,
+    hasNewChanges: Boolean,
+    onForegroundServiceButtonClicked: (Expandable) -> Unit,
+): FooterActionsForegroundServicesButtonViewModel {
+    val text =
+        icuMessageFormat(
+            qsThemedContext.resources,
+            R.string.fgs_manager_footer_label,
+            foregroundServicesCount,
+        )
+
+    return FooterActionsForegroundServicesButtonViewModel(
+        foregroundServicesCount,
+        text = text,
+        displayText = securityModel == null,
+        hasNewChanges = hasNewChanges,
+        onForegroundServiceButtonClicked,
+    )
+}
+
+fun userSwitcherButtonViewModel(
+    qsThemedContext: Context,
+    status: UserSwitcherStatusModel.Enabled,
+    onUserSwitcherClicked: (Expandable) -> Unit,
+): FooterActionsButtonViewModel {
+    val icon = status.currentUserImage!!
+    return FooterActionsButtonViewModel(
+        id = R.id.multi_user_switch,
+        icon =
+            Icon.Loaded(
+                icon,
+                ContentDescription.Loaded(
+                    userSwitcherContentDescription(qsThemedContext, status.currentUserName)
+                ),
+            ),
+        iconTint = null,
+        backgroundColor = R.attr.shadeInactive,
+        onClick = onUserSwitcherClicked,
+    )
+}
+
+private fun userSwitcherContentDescription(
+    qsThemedContext: Context,
+    currentUser: String?
+): String? {
+    return currentUser?.let { user ->
+        qsThemedContext.getString(R.string.accessibility_quick_settings_user, user)
+    }
+}
+
+fun settingsButtonViewModel(
+    qsThemedContext: Context,
+    onSettingsButtonClicked: (Expandable) -> Unit,
+): FooterActionsButtonViewModel {
+    return FooterActionsButtonViewModel(
+        id = R.id.settings_button_container,
+        Icon.Resource(
+            R.drawable.ic_settings,
+            ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
+        ),
+        iconTint =
+            Utils.getColorAttrDefaultColor(
+                qsThemedContext,
+                R.attr.onShadeInactiveVariant,
+            ),
+        backgroundColor = R.attr.shadeInactive,
+        onSettingsButtonClicked,
+    )
+}
+
+fun powerButtonViewModel(
+    qsThemedContext: Context,
+    onPowerButtonClicked: (Expandable) -> Unit,
+): FooterActionsButtonViewModel {
+    return FooterActionsButtonViewModel(
+        id = R.id.pm_lite,
+        Icon.Resource(
+            android.R.drawable.ic_lock_power_off,
+            ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+        ),
+        iconTint =
+            Utils.getColorAttrDefaultColor(
+                qsThemedContext,
+                R.attr.onShadeActive,
+            ),
+        backgroundColor = R.attr.shadeActive,
+        onPowerButtonClicked,
+    )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 5a9c0a1..f8e0159 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -23,7 +23,10 @@
 import android.content.res.ColorStateList
 import android.content.res.Configuration
 import android.content.res.Resources.ID_NULL
+import android.graphics.Color
+import android.graphics.PorterDuff
 import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
 import android.graphics.drawable.RippleDrawable
 import android.os.Trace
 import android.service.quicksettings.Tile
@@ -44,7 +47,6 @@
 import androidx.annotation.VisibleForTesting
 import com.android.settingslib.Utils
 import com.android.systemui.FontSizeUtils
-import com.android.systemui.res.R
 import com.android.systemui.animation.LaunchableView
 import com.android.systemui.animation.LaunchableViewDelegate
 import com.android.systemui.plugins.qs.QSIconView
@@ -53,6 +55,7 @@
 import com.android.systemui.plugins.qs.QSTileView
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.tileimpl.QSIconViewImpl.QS_ANIM_LENGTH
+import com.android.systemui.res.R
 import java.util.Objects
 
 private const val TAG = "QSTileViewImpl"
@@ -67,6 +70,7 @@
         private const val LABEL_NAME = "label"
         private const val SECONDARY_LABEL_NAME = "secondaryLabel"
         private const val CHEVRON_NAME = "chevron"
+        private const val OVERLAY_NAME = "overlay"
         const val UNAVAILABLE_ALPHA = 0.3f
         @VisibleForTesting
         internal const val TILE_STATE_RES_PREFIX = "tile_states_"
@@ -97,6 +101,13 @@
     private val colorInactive = Utils.getColorAttrDefaultColor(context, R.attr.shadeInactive)
     private val colorUnavailable = Utils.getColorAttrDefaultColor(context, R.attr.shadeDisabled)
 
+    private val overlayColorActive = Utils.applyAlpha(
+        /* alpha= */ 0.11f,
+        Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive))
+    private val overlayColorInactive = Utils.applyAlpha(
+        /* alpha= */ 0.08f,
+        Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactive))
+
     private val colorLabelActive = Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive)
     private val colorLabelInactive = Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactive)
     private val colorLabelUnavailable =
@@ -123,8 +134,13 @@
     protected var showRippleEffect = true
 
     private lateinit var ripple: RippleDrawable
-    private lateinit var colorBackgroundDrawable: Drawable
-    private var paintColor: Int = 0
+    private lateinit var backgroundDrawable: LayerDrawable
+    private lateinit var backgroundBaseDrawable: Drawable
+    private lateinit var backgroundOverlayDrawable: Drawable
+
+    private var backgroundColor: Int = 0
+    private var backgroundOverlayColor: Int = 0
+
     private val singleAnimator: ValueAnimator = ValueAnimator().apply {
         setDuration(QS_ANIM_LENGTH)
         addUpdateListener { animation ->
@@ -134,7 +150,8 @@
                 animation.getAnimatedValue(BACKGROUND_NAME) as Int,
                 animation.getAnimatedValue(LABEL_NAME) as Int,
                 animation.getAnimatedValue(SECONDARY_LABEL_NAME) as Int,
-                animation.getAnimatedValue(CHEVRON_NAME) as Int
+                animation.getAnimatedValue(CHEVRON_NAME) as Int,
+                animation.getAnimatedValue(OVERLAY_NAME) as Int,
             )
         }
     }
@@ -263,7 +280,12 @@
 
     fun createTileBackground(): Drawable {
         ripple = mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
-        colorBackgroundDrawable = ripple.findDrawableByLayerId(R.id.background)
+        backgroundDrawable = ripple.findDrawableByLayerId(R.id.background) as LayerDrawable
+        backgroundBaseDrawable =
+            backgroundDrawable.findDrawableByLayerId(R.id.qs_tile_background_base)
+        backgroundOverlayDrawable =
+            backgroundDrawable.findDrawableByLayerId(R.id.qs_tile_background_overlay)
+        backgroundOverlayDrawable.mutate().setTintMode(PorterDuff.Mode.SRC)
         return ripple
     }
 
@@ -343,10 +365,10 @@
             ripple.also {
                 // In case that the colorBackgroundDrawable was used as the background, make sure
                 // it has the correct callback instead of null
-                colorBackgroundDrawable.callback = it
+                backgroundDrawable.callback = it
             }
         } else {
-            colorBackgroundDrawable
+            backgroundDrawable
         }
     }
 
@@ -512,7 +534,7 @@
                 singleAnimator.setValues(
                         colorValuesHolder(
                                 BACKGROUND_NAME,
-                                paintColor,
+                                backgroundColor,
                                 getBackgroundColorForState(state.state, state.disabledByPolicy)
                         ),
                         colorValuesHolder(
@@ -529,6 +551,11 @@
                                 CHEVRON_NAME,
                                 chevronView.imageTintList?.defaultColor ?: 0,
                                 getChevronColorForState(state.state, state.disabledByPolicy)
+                        ),
+                        colorValuesHolder(
+                                OVERLAY_NAME,
+                                backgroundOverlayColor,
+                                getOverlayColorForState(state.state)
                         )
                     )
                 singleAnimator.start()
@@ -537,7 +564,8 @@
                     getBackgroundColorForState(state.state, state.disabledByPolicy),
                     getLabelColorForState(state.state, state.disabledByPolicy),
                     getSecondaryLabelColorForState(state.state, state.disabledByPolicy),
-                    getChevronColorForState(state.state, state.disabledByPolicy)
+                    getChevronColorForState(state.state, state.disabledByPolicy),
+                    getOverlayColorForState(state.state)
                 )
             }
         }
@@ -555,17 +583,19 @@
         backgroundColor: Int,
         labelColor: Int,
         secondaryLabelColor: Int,
-        chevronColor: Int
+        chevronColor: Int,
+        overlayColor: Int,
     ) {
         setColor(backgroundColor)
         setLabelColor(labelColor)
         setSecondaryLabelColor(secondaryLabelColor)
         setChevronColor(chevronColor)
+        setOverlayColor(overlayColor)
     }
 
     private fun setColor(color: Int) {
-        colorBackgroundDrawable.mutate().setTint(color)
-        paintColor = color
+        backgroundBaseDrawable.mutate().setTint(color)
+        backgroundColor = color
     }
 
     private fun setLabelColor(color: Int) {
@@ -580,6 +610,11 @@
         chevronView.imageTintList = ColorStateList.valueOf(color)
     }
 
+    private fun setOverlayColor(overlayColor: Int) {
+        backgroundOverlayDrawable.setTint(overlayColor)
+        backgroundOverlayColor = overlayColor
+    }
+
     private fun loadSideViewDrawableIfNecessary(state: QSTile.State) {
         if (state.sideViewCustomDrawable != null) {
             customDrawableView.setImageDrawable(state.sideViewCustomDrawable)
@@ -654,9 +689,17 @@
     private fun getChevronColorForState(state: Int, disabledByPolicy: Boolean = false): Int =
             getSecondaryLabelColorForState(state, disabledByPolicy)
 
+    private fun getOverlayColorForState(state: Int): Int {
+        return when (state) {
+            Tile.STATE_ACTIVE -> overlayColorActive
+            Tile.STATE_INACTIVE -> overlayColorInactive
+            else -> Color.TRANSPARENT
+        }
+    }
+
     @VisibleForTesting
     internal fun getCurrentColors(): List<Int> = listOf(
-            paintColor,
+            backgroundColor,
             label.currentTextColor,
             secondaryLabel.currentTextColor,
             chevronView.imageTintList?.defaultColor ?: 0
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/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index d862f56..18d2f30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -39,7 +39,6 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
@@ -53,6 +52,7 @@
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogViewModel;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.BluetoothController;
 
 import java.util.List;
@@ -198,6 +198,7 @@
         }
 
         state.expandedAccessibilityClassName = Switch.class.getName();
+        state.forceExpandIcon = mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG);
     }
 
     /**
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/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/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/ObservableTransitionState.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
index f704894..3927873 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
@@ -42,13 +42,6 @@
          * scene, this value will remain true after the pointer is no longer touching the screen and
          * will be true in any transition created to animate back to the original position.
          */
-        val isInitiatedByUserInput: Boolean,
-
-        /**
-         * Whether user input is currently driving the transition. For example, if a user is
-         * dragging a pointer, this emits true. Once they lift their finger, this emits false while
-         * the transition completes/settles.
-         */
-        val isUserInputOngoing: Flow<Boolean>,
+        val isUserInputDriven: Boolean,
     ) : ObservableTransitionState()
 }
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/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 9325e18..00d480a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.content.ComponentName;
+import android.content.ContentProvider;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.HardwareRenderer;
@@ -44,10 +45,10 @@
 import com.android.internal.app.ChooserActivity;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.view.OneShotPreDrawListener;
-import com.android.systemui.res.R;
 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.screenshot.CropView.CropBoundary;
 import com.android.systemui.screenshot.ScrollCaptureController.LongScreenshot;
 import com.android.systemui.settings.UserTracker;
@@ -421,13 +422,15 @@
             Log.e(TAG, "failed to export", e);
             return;
         }
+        Uri exported = ContentProvider.getUriWithoutUserId(result.uri);
+        Log.e(TAG, action + " uri=" + exported);
 
         switch (action) {
             case EDIT:
-                doEdit(result.uri);
+                doEdit(exported);
                 break;
             case SHARE:
-                doShare(result.uri);
+                doShare(exported);
                 break;
             case SAVE:
                 // Nothing more to do
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 4b3bd0b..127a57e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -303,6 +303,13 @@
     private String mPackageName = "";
     private BroadcastReceiver mCopyBroadcastReceiver;
 
+    // When false, the screenshot is taken without showing the ui. Note that this only applies to
+    // external displays, as on the default one the UI should **always** be shown.
+    // This is needed in case of screenshot during display mirroring, as adding another window to
+    // the external display makes mirroring stop.
+    // When there is a way to distinguish between displays that are mirroring or extending, this
+    // can be removed and we can directly show the ui only in the extended case.
+    private final Boolean mShowUIOnExternalDisplay;
     /** Tracks config changes that require re-creating UI */
     private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
             ActivityInfo.CONFIG_ORIENTATION
@@ -335,7 +342,8 @@
             AssistContentRequester assistContentRequester,
             MessageContainerController messageContainerController,
             Provider<ScreenshotSoundController> screenshotSoundController,
-            @Assisted int displayId
+            @Assisted int displayId,
+            @Assisted boolean showUIOnExternalDisplay
     ) {
         mScreenshotSmartActions = screenshotSmartActions;
         mNotificationsController = screenshotNotificationsController;
@@ -401,6 +409,7 @@
         mContext.registerReceiver(mCopyBroadcastReceiver, new IntentFilter(
                         ClipboardOverlayController.COPY_OVERLAY_ACTION),
                 ClipboardOverlayController.SELF_PERMISSION, null, Context.RECEIVER_NOT_EXPORTED);
+        mShowUIOnExternalDisplay = showUIOnExternalDisplay;
     }
 
     void handleScreenshot(ScreenshotData screenshot, Consumer<Uri> finisher,
@@ -448,6 +457,23 @@
 
         prepareViewForNewScreenshot(screenshot, oldPackageName);
 
+        if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && screenshot.getTaskId() >= 0) {
+            mAssistContentRequester.requestAssistContent(screenshot.getTaskId(),
+                    new AssistContentRequester.Callback() {
+                        @Override
+                        public void onAssistContentAvailable(AssistContent assistContent) {
+                            screenshot.setContextUrl(assistContent.getWebUri());
+                        }
+                    });
+        }
+
+        if (!shouldShowUi()) {
+            saveScreenshotInWorkerThread(
+                screenshot.getUserHandle(), finisher, this::logSuccessOnActionsReady,
+                (ignored) -> {});
+            return;
+        }
+
         saveScreenshotInWorkerThread(screenshot.getUserHandle(), finisher,
                 this::showUiOnActionsReady, this::showUiOnQuickShareActionReady);
 
@@ -482,22 +508,16 @@
                 screenshot.getUserHandle()));
         mScreenshotView.setScreenshot(screenshot);
 
-        if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && screenshot.getTaskId() >= 0) {
-            mAssistContentRequester.requestAssistContent(screenshot.getTaskId(),
-                    new AssistContentRequester.Callback() {
-                        @Override
-                        public void onAssistContentAvailable(AssistContent assistContent) {
-                            screenshot.setContextUrl(assistContent.getWebUri());
-                        }
-                    });
-        }
-
         // ignore system bar insets for the purpose of window layout
         mWindow.getDecorView().setOnApplyWindowInsetsListener(
                 (v, insets) -> WindowInsets.CONSUMED);
         mScreenshotHandler.cancelTimeout(); // restarted after animation
     }
 
+    private boolean shouldShowUi() {
+        return mDisplayId == Display.DEFAULT_DISPLAY || mShowUIOnExternalDisplay;
+    }
+
     void prepareViewForNewScreenshot(ScreenshotData screenshot, String oldPackageName) {
         withWindowAttached(() -> {
             if (mUserManager.isManagedProfile(screenshot.getUserHandle().getIdentifier())) {
@@ -1199,7 +1219,13 @@
     /** Injectable factory to create screenshot controller instances for a specific display. */
     @AssistedFactory
     public interface Factory {
-        /** Creates an instance of the controller for that specific displayId. */
-        ScreenshotController create(int displayId);
+        /**
+         * Creates an instance of the controller for that specific displayId.
+         *
+         * @param displayId:               display to capture
+         * @param showUIOnExternalDisplay: Whether the UI should be shown if this is an external
+         *                                 display.
+         */
+        ScreenshotController create(int displayId, boolean showUIOnExternalDisplay);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
index 03c3f7a..abe40ff 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
@@ -135,7 +135,9 @@
     }
 
     private fun getScreenshotController(id: Int): ScreenshotController {
-        return screenshotControllers.computeIfAbsent(id) { screenshotControllerFactory.create(id) }
+        return screenshotControllers.computeIfAbsent(id) {
+            screenshotControllerFactory.create(id, /* showUIOnExternalDisplay= */ false)
+        }
     }
 
     /** For java compatibility only. see [executeScreenshots] */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 0be2265..75d52cb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -132,7 +132,8 @@
         if (mFeatureFlags.isEnabled(MULTI_DISPLAY_SCREENSHOT)) {
             mScreenshot = null;
         } else {
-            mScreenshot = screenshotControllerFactory.create(Display.DEFAULT_DISPLAY);
+            mScreenshot = screenshotControllerFactory.create(
+                    Display.DEFAULT_DISPLAY, /* showUIOnExternalDisplay= */ false);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
index bd592c9..cf1fbe3 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.settings
 
+import com.android.systemui.util.annotations.WeaklyReferencedCallback
+
 import android.content.Context
 import android.content.pm.UserInfo
 import android.os.UserHandle
@@ -64,6 +66,7 @@
     /**
      * Callback for notifying of changes.
      */
+    @WeaklyReferencedCallback
     interface Callback {
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 2ef83dd..ba0cf08 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -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;
@@ -3379,6 +3381,7 @@
         mBlockingExpansionForCurrentTouch = isTracking();
     }
 
+    @NeverCompile
     @Override
     public void dump(PrintWriter pw, String[] args) {
         pw.println(TAG + ":");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 5414b3f..d05dfe2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -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;
@@ -106,7 +106,7 @@
     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;
@@ -185,7 +185,7 @@
             SystemClock clock,
             BouncerMessageInteractor bouncerMessageInteractor,
             BouncerLogger bouncerLogger,
-            KeyEventInteractor keyEventInteractor,
+            SysUIKeyEventHandler sysUIKeyEventHandler,
             PrimaryBouncerInteractor primaryBouncerInteractor,
             AlternateBouncerInteractor alternateBouncerInteractor) {
         mLockscreenShadeTransitionController = transitionController;
@@ -214,7 +214,7 @@
         mNotificationInsetsController = notificationInsetsController;
         mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
         mFeatureFlags = featureFlags;
-        mKeyEventInteractor = keyEventInteractor;
+        mSysUIKeyEventHandler = sysUIKeyEventHandler;
         mPrimaryBouncerInteractor = primaryBouncerInteractor;
         mAlternateBouncerInteractor = alternateBouncerInteractor;
 
@@ -529,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/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 6117f9f..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
@@ -261,7 +261,7 @@
                 when (state) {
                     is ObservableTransitionState.Idle -> false
                     is ObservableTransitionState.Transition ->
-                        state.isInitiatedByUserInput &&
+                        state.isUserInputDriven &&
                             (state.toScene == sceneKey || state.fromScene == sceneKey)
                 }
             }
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/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/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/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/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/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
index 9d56a8e..362786e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
@@ -115,6 +115,7 @@
      *
      * @deprecated Use {@link #onRankingApplied()} instead.
      */
+    @Deprecated
     default void onRankingUpdate(NotificationListenerService.RankingMap rankingMap) {
     }
 
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 733d774..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
@@ -53,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;
@@ -95,6 +96,7 @@
         CoordinatorsModule.class,
         KeyguardNotificationVisibilityProviderModule.class,
         ShadeEventsModule.class,
+        NotificationDataLayerModule.class,
         NotifPipelineChoreographerModule.class,
         NotificationSectionHeadersModule.class,
         NotificationListViewModelModule.class,
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 a77e67b..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,26 +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.Flags.NEW_AOD_TRANSITION
-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
@@ -60,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
@@ -79,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,
@@ -89,7 +85,7 @@
     private val bubblesOptional: Optional<Bubbles>,
     demoModeController: DemoModeController,
     darkIconDispatcher: DarkIconDispatcher,
-    private val featureFlags: FeatureFlags,
+    private val featureFlags: FeatureFlagsClassic,
     private val statusBarWindowController: StatusBarWindowController,
     private val screenOffAnimationController: ScreenOffAnimationController,
     private val shelfIconsViewModel: NotificationIconContainerShelfViewModel,
@@ -98,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
@@ -119,7 +113,6 @@
     private var aodBindJob: DisposableHandle? = null
     private var aodIconAppearTranslation = 0
     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)
@@ -160,8 +152,11 @@
             NotificationIconContainerViewBinder.bind(
                 aodIcons,
                 aodIconsViewModel,
+                configurationController,
+                dozeParameters,
+                featureFlags,
+                screenOffAnimationController,
             )
-        updateAodIconsVisibility(animate = false, forceUpdate = changed)
         if (changed) {
             updateAodNotificationIcons()
         }
@@ -176,6 +171,10 @@
             NotificationIconContainerViewBinder.bind(
                 icons,
                 shelfIconsViewModel,
+                configurationController,
+                dozeParameters,
+                featureFlags,
+                screenOffAnimationController,
             )
             shelfIcons = icons
         }
@@ -249,20 +248,8 @@
         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) = unsupported
 
-    override fun onStateChanged(newState: Int) {
-        updateAodIconsVisibility(animate = false, forceUpdate = false)
-    }
-
     override fun onThemeChanged() {
         reloadAodColor()
         updateAodIconColors()
@@ -272,53 +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
-            if (!featureFlags.isEnabled(NEW_AOD_TRANSITION)) {
-                // 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)
@@ -352,6 +297,10 @@
         NotificationIconContainerViewBinder.bind(
             notificationIcons!!,
             statusBarIconsViewModel,
+            configurationController,
+            dozeParameters,
+            featureFlags,
+            screenOffAnimationController,
         )
     }
 
@@ -602,17 +551,6 @@
         v.setDecorColor(tint)
     }
 
-    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,69 +573,7 @@
         }
     }
 
-    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) {
-                if (featureFlags.isEnabled(NEW_AOD_TRANSITION)) {
-                    // Let's make sure the icon are translated to 0, since we cancelled it above
-                    animateInAodIconTranslation()
-                    if (aodIconsVisible) {
-                        CrossFadeHelper.fadeIn(aodIcons)
-                    } else {
-                        CrossFadeHelper.fadeOut(aodIcons)
-                    }
-                } else {
-                    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
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 f8ff3e3..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,12 +15,27 @@
  */
 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]. */
@@ -28,11 +43,144 @@
     fun bind(
         view: NotificationIconContainer,
         viewModel: NotificationIconContainerViewModel,
+        configurationController: ConfigurationController,
+        dozeParameters: DozeParameters,
+        featureFlags: FeatureFlagsClassic,
+        screenOffAnimationController: ScreenOffAnimationController,
     ): DisposableHandle {
         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 90507fc..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,19 +15,48 @@
  */
 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. */
+@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,
@@ -35,4 +64,97 @@
         ) { 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 49f262d..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,12 +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 {
     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 ee57b78..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
@@ -17,9 +17,11 @@
 
 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
@@ -35,4 +37,9 @@
         ) { 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 6f8ce4b..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,6 +15,7 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import com.android.systemui.util.ui.AnimatedValue
 import kotlinx.coroutines.flow.Flow
 
 /**
@@ -24,4 +25,22 @@
 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 847d948..661768d 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
@@ -351,12 +351,21 @@
 
     @Override
     public long performRemoveAnimation(long duration, long delay, float translationDirection,
-            boolean isHeadsUpAnimation, Runnable onFinishedRunnable,
+            boolean isHeadsUpAnimation, Runnable onStartedRunnable, Runnable onFinishedRunnable,
             AnimatorListenerAdapter animationListener) {
         enableAppearDrawing(true);
         mIsHeadsUpAnimation = isHeadsUpAnimation;
-        startAppearAnimation(false /* isAppearing */, translationDirection,
-                delay, duration, onFinishedRunnable, animationListener);
+        if (mDrawingAppearAnimation) {
+            startAppearAnimation(false /* isAppearing */, translationDirection,
+                    delay, duration, onStartedRunnable, onFinishedRunnable, animationListener);
+        } else {
+            if (onStartedRunnable != null) {
+                onStartedRunnable.run();
+            }
+            if (onFinishedRunnable != null) {
+                onFinishedRunnable.run();
+            }
+        }
         return 0;
     }
 
@@ -365,12 +374,14 @@
             Runnable onFinishRunnable) {
         enableAppearDrawing(true);
         mIsHeadsUpAnimation = isHeadsUpAppear;
-        startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay,
-                duration, null, null);
+        if (mDrawingAppearAnimation) {
+            startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay,
+                    duration, null, null, null);
+        }
     }
 
     private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
-            long duration, final Runnable onFinishedRunnable,
+            long duration, final Runnable onStartedRunnable, final Runnable onFinishedRunnable,
             AnimatorListenerAdapter animationListener) {
         mAnimationTranslationY = translationDirection * getActualHeight();
         cancelAppearAnimation();
@@ -434,6 +445,9 @@
 
             @Override
             public void onAnimationStart(Animator animation) {
+                if (onStartedRunnable != null) {
+                    onStartedRunnable.run();
+                }
                 mRunWithoutInterruptions = true;
                 Configuration.Builder builder = Configuration.Builder
                         .withView(getCujType(isAppearing), ActivatableNotificationView.this);
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 061132f..9340b85 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.
@@ -2930,6 +2927,7 @@
             long delay,
             float translationDirection,
             boolean isHeadsUpAnimation,
+            Runnable onStartedRunnable,
             Runnable onFinishedRunnable,
             AnimatorListenerAdapter animationListener) {
         if (mMenuRow != null && mMenuRow.isMenuVisible()) {
@@ -2937,10 +2935,16 @@
             if (anim != null) {
                 anim.addListener(new AnimatorListenerAdapter() {
                     @Override
+                    public void onAnimationStart(Animator animation) {
+                        if (onStartedRunnable != null) {
+                            onStartedRunnable.run();
+                        }
+                    }
+                    @Override
                     public void onAnimationEnd(Animator animation) {
                         ExpandableNotificationRow.super.performRemoveAnimation(
                                 duration, delay, translationDirection, isHeadsUpAnimation,
-                                onFinishedRunnable, animationListener);
+                                null, onFinishedRunnable, animationListener);
                     }
                 });
                 anim.start();
@@ -2948,7 +2952,7 @@
             }
         }
         return super.performRemoveAnimation(duration, delay, translationDirection,
-                isHeadsUpAnimation, onFinishedRunnable, animationListener);
+                isHeadsUpAnimation, onStartedRunnable, onFinishedRunnable, animationListener);
     }
 
     @Override
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 f2f55a8..6edab4d 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
@@ -69,6 +69,9 @@
     private boolean mClipToActualHeight = true;
     private boolean mChangingPosition = false;
     private ViewGroup mTransientContainer;
+
+    // Needs to be added as transient view when removed from parent, because it's in animation
+    private boolean mInRemovalAnimation;
     private boolean mInShelf;
     private boolean mTransformingInShelf;
     protected float mContentTransformationAmount;
@@ -381,6 +384,7 @@
      */
     public abstract long performRemoveAnimation(long duration,
             long delay, float translationDirection, boolean isHeadsUpAnimation,
+            Runnable onStartedRunnable,
             Runnable onFinishedRunnable,
             AnimatorListenerAdapter animationListener);
 
@@ -604,6 +608,25 @@
     }
 
     /**
+     * Add the view to a transient container.
+     */
+    public void addToTransientContainer(ViewGroup container, int index) {
+        container.addTransientView(this, index);
+        setTransientContainer(container);
+    }
+
+    /**
+     * @return If the view is in a process of removal animation.
+     */
+    public boolean inRemovalAnimation() {
+        return mInRemovalAnimation;
+    }
+
+    public void setInRemovalAnimation(boolean inRemovalAnimation) {
+        mInRemovalAnimation = inRemovalAnimation;
+    }
+
+    /**
      * @return true if the group's expansion state is changing, false otherwise.
      */
     public boolean isGroupExpansionChanging() {
@@ -837,6 +860,7 @@
                 pw.println();
             }
             if (DUMP_VERBOSE) {
+                pw.println("mInRemovalAnimation: " + mInRemovalAnimation);
                 pw.println("mClipTopAmount: " + mClipTopAmount);
                 pw.println("mClipBottomAmount " + mClipBottomAmount);
                 pw.println("mClipToActualHeight: " + mClipToActualHeight);
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..aabf295 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;
     }
 
@@ -236,9 +237,13 @@
     @Override
     public long performRemoveAnimation(long duration, long delay,
             float translationDirection, boolean isHeadsUpAnimation,
+            Runnable onStartedRunnable,
             Runnable onFinishedRunnable,
             AnimatorListenerAdapter animationListener) {
         // TODO: Use duration
+        if (onStartedRunnable != null) {
+            onStartedRunnable.run();
+        }
         setContentVisible(false, true /* animate */, (cancelled) -> onFinishedRunnable.run());
         return 0;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
index 5d46f52..bae5baa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
@@ -25,9 +25,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.notification.row.ExpandableView
 
-/**
- * Root view to insert Lock screen media controls into the notification stack.
- */
+/** Root view to insert Lock screen media controls into the notification stack. */
 class MediaContainerView(context: Context, attrs: AttributeSet?) : ExpandableView(context, attrs) {
 
     override var clipHeight = 0
@@ -46,8 +44,8 @@
     }
 
     private fun updateResources() {
-        cornerRadius = context.resources
-                .getDimensionPixelSize(R.dimen.notification_corner_radius).toFloat()
+        cornerRadius =
+            context.resources.getDimensionPixelSize(R.dimen.notification_corner_radius).toFloat()
     }
 
     public override fun updateClipping() {
@@ -70,18 +68,23 @@
     }
 
     override fun performRemoveAnimation(
-            duration: Long,
-            delay: Long,
-            translationDirection: Float,
-            isHeadsUpAnimation: Boolean,
-            onFinishedRunnable: Runnable?,
-            animationListener: AnimatorListenerAdapter?
+        duration: Long,
+        delay: Long,
+        translationDirection: Float,
+        isHeadsUpAnimation: Boolean,
+        onStartedRunnable: Runnable?,
+        onFinishedRunnable: Runnable?,
+        animationListener: AnimatorListenerAdapter?
     ): Long {
         return 0
     }
 
-    override fun performAddAnimation(delay: Long, duration: Long, isHeadsUpAppear: Boolean,
-                                     onEnd: Runnable?) {
+    override fun performAddAnimation(
+        delay: Long,
+        duration: Long,
+        isHeadsUpAppear: Boolean,
+        onEnd: Runnable?
+    ) {
         // No animation, it doesn't need it, this would be local
     }
-}
\ No newline at end of file
+}
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 78d7558..79f8f22 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
@@ -20,6 +20,7 @@
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL;
+import static com.android.systemui.flags.Flags.UNCLEARED_TRANSIENT_HUN_FIX;
 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
 import static com.android.systemui.util.DumpUtilsKt.println;
@@ -86,12 +87,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 +107,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 +201,8 @@
     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;
 
@@ -576,6 +577,7 @@
         mSplitShadeStateController = splitShadeStateController;
         updateSplitNotificationShade();
     }
+    private FeatureFlags mFeatureFlags;
 
     private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
             new ExpandableView.OnHeightChangedListener() {
@@ -628,16 +630,16 @@
     public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
         super(context, attrs, 0, 0);
         Resources res = getResources();
-        FeatureFlags featureFlags = Dependency.get(FeatureFlags.class);
-        mIsSmallLandscapeLockscreenEnabled = featureFlags.isEnabled(
+        mFeatureFlags = Dependency.get(FeatureFlags.class);
+        mIsSmallLandscapeLockscreenEnabled = mFeatureFlags.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);
+        mDebugLines = mFeatureFlags.isEnabled(Flags.NSSL_DEBUG_LINES);
+        mNewAodTransition = mFeatureFlags.isEnabled(Flags.NEW_AOD_TRANSITION);
+        mDebugRemoveAnimation = mFeatureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
+        mSensitiveRevealAnimEndabled = mFeatureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM);
         mAnimatedInsets =
-                new ViewRefactorFlag(featureFlags, Flags.ANIMATED_NOTIFICATION_SHADE_INSETS);
-        mShelfRefactor = new ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
+                new RefactorFlag(mFeatureFlags, Flags.ANIMATED_NOTIFICATION_SHADE_INSETS);
+        mShelfRefactor = new RefactorFlag(mFeatureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
         mSectionsManager = Dependency.get(NotificationSectionsManager.class);
         mScreenOffAnimationController =
                 Dependency.get(ScreenOffAnimationController.class);
@@ -2779,8 +2781,7 @@
         if (animationGenerated) {
             if (!mSwipedOutViews.contains(child) || !isFullySwipedOut(child)) {
                 logAddTransientChild(child, container);
-                container.addTransientView(child, 0);
-                child.setTransientContainer(container);
+                child.addToTransientContainer(container, 0);
             }
         } else {
             mSwipedOutViews.remove(child);
@@ -2870,7 +2871,8 @@
      * Generate a remove animation for a child view.
      *
      * @param child The view to generate the remove animation for.
-     * @return Whether an animation was generated.
+     * @return Whether a new animation was generated or an existing animation was detected by this
+     * method. We need this to determine if a transient view is needed.
      */
     boolean generateRemoveAnimation(ExpandableView child) {
         String key = "";
@@ -2887,10 +2889,23 @@
             mAddedHeadsUpChildren.remove(child);
             return false;
         }
-        if (isClickedHeadsUp(child)) {
-            // An animation is already running, add it transiently
-            mClearTransientViewsWhenFinished.add(child);
-            return true;
+        if (mFeatureFlags.isEnabled(UNCLEARED_TRANSIENT_HUN_FIX)) {
+            // Skip adding animation for clicked heads up notifications when the
+            // Shade is closed, because the animation event is generated in
+            // generateHeadsUpAnimationEvents. Only report that an animation was
+            // actually generated (thus requesting the transient view be added)
+            // if a removal animation is in progress.
+            if (!isExpanded() && isClickedHeadsUp(child)) {
+                // An animation is already running, add it transiently
+                mClearTransientViewsWhenFinished.add(child);
+                return child.inRemovalAnimation();
+            }
+        } else {
+            if (isClickedHeadsUp(child)) {
+                // An animation is already running, add it transiently
+                mClearTransientViewsWhenFinished.add(child);
+                return true;
+            }
         }
         if (mDebugRemoveAnimation) {
             Log.d(TAG, "generateRemove " + key
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 9695cb1..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;
@@ -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;
@@ -719,7 +719,7 @@
         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;
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 8ca1852..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;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 69453c6..e94258f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
+import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
+import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -346,21 +349,19 @@
             ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents) {
         boolean needsCustomAnimation = false;
         for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) {
-            final ExpandableView changingView = (ExpandableView) event.mChangingView;
+            final ExpandableView changingView = event.mChangingView;
             boolean loggable = false;
             boolean isHeadsUp = false;
-            boolean isGroupChild = false;
             String key = null;
             if (changingView instanceof ExpandableNotificationRow && mLogger != null) {
                 loggable = true;
                 isHeadsUp = ((ExpandableNotificationRow) changingView).isHeadsUp();
-                isGroupChild = changingView.isChildInGroup();
                 key = ((ExpandableNotificationRow) changingView).getEntry().getKey();
             }
             if (event.animationType ==
                     NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) {
 
-                // This item is added, initialize it's properties.
+                // This item is added, initialize its properties.
                 ExpandableViewState viewState = changingView.getViewState();
                 if (viewState == null || viewState.gone) {
                     // The position for this child was never generated, let's continue.
@@ -374,7 +375,11 @@
 
             } else if (event.animationType ==
                     NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) {
-                if (changingView.getVisibility() != View.VISIBLE) {
+                int changingViewVisibility = changingView.getVisibility();
+                if (loggable) {
+                    mLogger.processAnimationEventsRemoval(key, changingViewVisibility, isHeadsUp);
+                }
+                if (changingViewVisibility != View.VISIBLE) {
                     changingView.removeFromTransientContainer();
                     continue;
                 }
@@ -410,30 +415,40 @@
                     translationDirection = Math.max(Math.min(translationDirection, 1.0f),-1.0f);
 
                 }
-                Runnable postAnimation = changingView::removeFromTransientContainer;
+                Runnable postAnimation;
+                Runnable startAnimation;
                 if (loggable) {
                     String finalKey = key;
-                    if (isHeadsUp) {
-                        mLogger.logHUNViewDisappearingWithRemoveEvent(key);
-                        postAnimation = () -> {
-                            mLogger.disappearAnimationEnded(finalKey);
-                            changingView.removeFromTransientContainer();
-                        };
-                    } else if (isGroupChild) {
-                        mLogger.groupChildRemovalEventProcessed(key);
-                        postAnimation = () -> {
-                            mLogger.groupChildRemovalAnimationEnded(finalKey);
-                            changingView.removeFromTransientContainer();
-                        };
-                    }
+                    final boolean finalIsHeadsHp = isHeadsUp;
+                    startAnimation = () -> {
+                        mLogger.animationStart(finalKey, "ANIMATION_TYPE_REMOVE", finalIsHeadsHp);
+                        changingView.setInRemovalAnimation(true);
+                    };
+                    postAnimation = () -> {
+                        mLogger.animationEnd(finalKey, "ANIMATION_TYPE_REMOVE", finalIsHeadsHp);
+                        changingView.setInRemovalAnimation(false);
+                        changingView.removeFromTransientContainer();
+                    };
+                } else {
+                    startAnimation = ()-> {
+                        changingView.setInRemovalAnimation(true);
+                    };
+                    postAnimation = () -> {
+                        changingView.setInRemovalAnimation(false);
+                        changingView.removeFromTransientContainer();
+                    };
                 }
                 changingView.performRemoveAnimation(ANIMATION_DURATION_APPEAR_DISAPPEAR,
                         0 /* delay */, translationDirection, false /* isHeadsUpAppear */,
-                        postAnimation, getGlobalAnimationFinishedListener());
+                        startAnimation, postAnimation, getGlobalAnimationFinishedListener());
                 needsCustomAnimation = true;
             } else if (event.animationType ==
                 NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) {
-                if (mHostLayout.isFullySwipedOut(changingView)) {
+                boolean isFullySwipedOut = mHostLayout.isFullySwipedOut(changingView);
+                if (loggable) {
+                    mLogger.processAnimationEventsRemoveSwipeOut(key, isFullySwipedOut, isHeadsUp);
+                }
+                if (isFullySwipedOut) {
                     changingView.removeFromTransientContainer();
                 }
             } else if (event.animationType == NotificationStackScrollLayout
@@ -442,7 +457,7 @@
                 row.prepareExpansionChanged();
             } else if (event.animationType == NotificationStackScrollLayout
                     .AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) {
-                // This item is added, initialize it's properties.
+                // This item is added, initialize its properties.
                 ExpandableViewState viewState = changingView.getViewState();
                 mTmpState.copyFrom(viewState);
                 if (event.headsUpFromBottom) {
@@ -464,22 +479,23 @@
                 }
 
                 mTmpState.applyToView(changingView);
-            } else if (event.animationType == NotificationStackScrollLayout
-                            .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR ||
-                    event.animationType == NotificationStackScrollLayout
-                            .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
+            } else if (event.animationType == ANIMATION_TYPE_HEADS_UP_DISAPPEAR
+                    || event.animationType == ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
                 mHeadsUpDisappearChildren.add(changingView);
                 Runnable endRunnable = null;
                 if (changingView.getParent() == null) {
-                    // This notification was actually removed, so we need to add it transiently
+                    // This notification was actually removed, so we need to add it
+                    // transiently
                     mHostLayout.addTransientView(changingView, 0);
                     changingView.setTransientContainer(mHostLayout);
                     mTmpState.initFrom(changingView);
                     endRunnable = changingView::removeFromTransientContainer;
                 }
+
                 boolean needsAnimation = true;
                 if (changingView instanceof ExpandableNotificationRow) {
-                    ExpandableNotificationRow row = (ExpandableNotificationRow) changingView;
+                    ExpandableNotificationRow row =
+                            (ExpandableNotificationRow) changingView;
                     if (row.isDismissed()) {
                         needsAnimation = false;
                     }
@@ -488,21 +504,43 @@
                     // We need to add the global animation listener, since once no animations are
                     // running anymore, the panel will instantly hide itself. We need to wait until
                     // the animation is fully finished for this though.
-                    Runnable postAnimation = endRunnable;
+                    final Runnable tmpEndRunnable = endRunnable;
+                    Runnable postAnimation;
+                    Runnable startAnimation;
                     if (loggable) {
-                        mLogger.logHUNViewDisappearing(key);
-
-                        Runnable finalEndRunnable = endRunnable;
                         String finalKey1 = key;
+                        final boolean finalIsHeadsUp = isHeadsUp;
+                        final String type =
+                                event.animationType == ANIMATION_TYPE_HEADS_UP_DISAPPEAR
+                                        ? "ANIMATION_TYPE_HEADS_UP_DISAPPEAR"
+                                        : "ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK";
+                        startAnimation = () -> {
+                            mLogger.animationStart(finalKey1, type, finalIsHeadsUp);
+                            changingView.setInRemovalAnimation(true);
+                        };
                         postAnimation = () -> {
-                            mLogger.disappearAnimationEnded(finalKey1);
-                            if (finalEndRunnable != null) finalEndRunnable.run();
+                            mLogger.animationEnd(finalKey1, type, finalIsHeadsUp);
+                            changingView.setInRemovalAnimation(false);
+                            if (tmpEndRunnable != null) {
+                                tmpEndRunnable.run();
+                            }
+                        };
+                    } else {
+                        postAnimation = () -> {
+                            changingView.setInRemovalAnimation(false);
+                            if (tmpEndRunnable != null) {
+                                tmpEndRunnable.run();
+                            }
+                        };
+                        startAnimation = () -> {
+                            changingView.setInRemovalAnimation(true);
                         };
                     }
                     long removeAnimationDelay = changingView.performRemoveAnimation(
                             ANIMATION_DURATION_HEADS_UP_DISAPPEAR,
                             0, 0.0f, true /* isHeadsUpAppear */,
-                            postAnimation, getGlobalAnimationFinishedListener());
+                            startAnimation, postAnimation,
+                            getGlobalAnimationFinishedListener());
                     mAnimationProperties.delay += removeAnimationDelay;
                 } else if (endRunnable != null) {
                     endRunnable.run();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
index 0b2c486..d635f89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
@@ -5,74 +5,104 @@
 import com.android.systemui.log.dagger.NotificationHeadsUpLog
 import com.android.systemui.log.dagger.NotificationRenderLog
 import com.android.systemui.statusbar.notification.logKey
+import com.android.systemui.util.visibilityString
 import javax.inject.Inject
 
-class StackStateLogger @Inject constructor(
+class StackStateLogger
+@Inject
+constructor(
     @NotificationHeadsUpLog private val buffer: LogBuffer,
     @NotificationRenderLog private val notificationRenderBuffer: LogBuffer
 ) {
-    fun logHUNViewDisappearing(key: String) {
-        buffer.log(TAG, LogLevel.INFO, {
-            str1 = logKey(key)
-        }, {
-            "Heads up view disappearing $str1 "
-        })
-    }
 
     fun logHUNViewAppearing(key: String) {
-        buffer.log(TAG, LogLevel.INFO, {
-            str1 = logKey(key)
-        }, {
-            "Heads up notification view appearing $str1 "
-        })
-    }
-
-    fun logHUNViewDisappearingWithRemoveEvent(key: String) {
-        buffer.log(TAG, LogLevel.ERROR, {
-            str1 = logKey(key)
-        }, {
-            "Heads up view disappearing $str1 for ANIMATION_TYPE_REMOVE"
-        })
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = logKey(key) },
+            { "Heads up notification view appearing $str1 " }
+        )
     }
 
     fun logHUNViewAppearingWithAddEvent(key: String) {
-        buffer.log(TAG, LogLevel.ERROR, {
-            str1 = logKey(key)
-        }, {
-            "Heads up view disappearing $str1 for ANIMATION_TYPE_ADD"
-        })
-    }
-
-    fun disappearAnimationEnded(key: String) {
-        buffer.log(TAG, LogLevel.INFO, {
-            str1 = logKey(key)
-        }, {
-            "Heads up notification disappear animation ended $str1 "
-        })
+        buffer.log(
+            TAG,
+            LogLevel.ERROR,
+            { str1 = logKey(key) },
+            { "Heads up view disappearing $str1 for ANIMATION_TYPE_ADD" }
+        )
     }
 
     fun appearAnimationEnded(key: String) {
-        buffer.log(TAG, LogLevel.INFO, {
-            str1 = logKey(key)
-        }, {
-            "Heads up notification appear animation ended $str1 "
-        })
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = logKey(key) },
+            { "Heads up notification appear animation ended $str1 " }
+        )
     }
 
-    fun groupChildRemovalEventProcessed(key: String) {
-        notificationRenderBuffer.log(TAG, LogLevel.DEBUG, {
-            str1 = logKey(key)
-        }, {
-            "Group Child Notification removal event processed $str1 for ANIMATION_TYPE_REMOVE"
-        })
+    fun processAnimationEventsRemoval(key: String, visibility: Int, isHeadsUp: Boolean) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                str1 = logKey(key)
+                int1 = visibility
+                bool1 = isHeadsUp
+            },
+            {
+                "ProcessAnimationEvents ANIMATION_TYPE_REMOVE for: $str1, " +
+                    "changingViewVisibility: ${visibilityString(int1)}, isHeadsUp: $bool1"
+            }
+        )
     }
-    fun groupChildRemovalAnimationEnded(key: String) {
-        notificationRenderBuffer.log(TAG, LogLevel.INFO, {
-            str1 = logKey(key)
-        }, {
-            "Group child notification removal animation ended $str1 "
-        })
+
+    fun processAnimationEventsRemoveSwipeOut(
+        key: String,
+        isFullySwipedOut: Boolean,
+        isHeadsUp: Boolean
+    ) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                str1 = logKey(key)
+                bool1 = isFullySwipedOut
+                bool2 = isHeadsUp
+            },
+            {
+                "ProcessAnimationEvents ANIMATION_TYPE_REMOVE_SWIPED_OUT for: $str1, " +
+                    "isFullySwipedOut: $bool1, isHeadsUp: $bool2"
+            }
+        )
+    }
+
+    fun animationStart(key: String?, animationType: String, isHeadsUp: Boolean) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                str1 = logKey(key)
+                str2 = animationType
+                bool1 = isHeadsUp
+            },
+            { "Animation Start, type: $str2, notif key: $str1, isHeadsUp: $bool1" }
+        )
+    }
+
+    fun animationEnd(key: String, animationType: String, isHeadsUp: Boolean) {
+        notificationRenderBuffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                str1 = logKey(key)
+                str2 = animationType
+                bool1 = isHeadsUp
+            },
+            { "Animation End, type: $str2, notif key: $str1, isHeadsUp: $bool1" }
+        )
     }
 }
 
-private const val TAG = "StackScroll"
\ No newline at end of file
+private const val TAG = "StackScroll"
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 6e6318e..9fb6c1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -239,6 +239,8 @@
 
 import dagger.Lazy;
 
+import dalvik.annotation.optimization.NeverCompile;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.List;
@@ -310,8 +312,8 @@
             };
 
     void onStatusBarWindowStateChanged(@WindowVisibleState int state) {
-        updateBubblesVisibility();
         mStatusBarWindowState = state;
+        updateBubblesVisibility();
     }
 
     @Override
@@ -1086,6 +1088,7 @@
      * @deprecated use {@link
      * WindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible} instead.
      */    @VisibleForTesting
+    @Deprecated
     void initShadeVisibilityListener() {
         mShadeController.setVisibilityListener(new ShadeController.ShadeVisibilityListener() {
             @Override
@@ -1723,7 +1726,8 @@
         StatusBarMode mode = mStatusBarModeRepository.getStatusBarMode().getValue();
         mBubblesOptional.ifPresent(bubbles -> bubbles.onStatusBarVisibilityChanged(
                 mode != StatusBarMode.LIGHTS_OUT
-                        && mode != StatusBarMode.LIGHTS_OUT_TRANSPARENT));
+                        && mode != StatusBarMode.LIGHTS_OUT_TRANSPARENT
+                        && mStatusBarWindowState != WINDOW_STATE_HIDDEN));
     }
 
     void checkBarMode(
@@ -1763,6 +1767,7 @@
         }
     }
 
+    @NeverCompile
     @Override
     public void dump(PrintWriter pwOriginal, String[] args) {
         IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
@@ -2599,7 +2604,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) {
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 1b9e5b3..5553270 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
@@ -36,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;
@@ -109,7 +109,7 @@
     private final ArrayList<Rect> mTintAreas = new ArrayList<>();
     private final Context mContext;
 
-    private final ViewRefactorFlag mShelfRefactor;
+    private final RefactorFlag mShelfRefactor;
 
     private final boolean mNewAodTransition;
 
@@ -150,7 +150,7 @@
         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;
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/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 62b2445..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;
@@ -1594,7 +1592,7 @@
             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/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
index 6dc8065..da91d6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
@@ -15,6 +15,9 @@
  */
 package com.android.systemui.statusbar.phone;
 
+import com.android.systemui.util.annotations.WeaklyReferencedCallback;
+
+@WeaklyReferencedCallback
 public interface StatusBarWindowCallback {
     /**
      * Invoked when the internal state of NotificationShadeWindowControllerImpl changes.
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/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 945cc6b..53b343c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -27,6 +27,7 @@
 import android.os.UserManager;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.WorkerThread;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.settingslib.bluetooth.BluetoothCallback;
@@ -36,6 +37,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.systemui.bluetooth.BluetoothLogger;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.settings.UserTracker;
@@ -81,6 +83,8 @@
     private int mState;
 
     private final BluetoothAdapter mAdapter;
+
+    private final Executor mBackgroundExecutor;
     /**
      */
     @Inject
@@ -90,6 +94,7 @@
             DumpManager dumpManager,
             BluetoothLogger logger,
             BluetoothRepository bluetoothRepository,
+            @Background Executor executor,
             @Main Looper mainLooper,
             @Nullable LocalBluetoothManager localBluetoothManager,
             @Nullable BluetoothAdapter bluetoothAdapter) {
@@ -98,6 +103,7 @@
         mBluetoothRepository = bluetoothRepository;
         mLocalBluetoothManager = localBluetoothManager;
         mHandler = new H(mainLooper);
+        mBackgroundExecutor = executor;
         if (mLocalBluetoothManager != null) {
             mLocalBluetoothManager.getEventManager().registerCallback(this);
             mLocalBluetoothManager.getProfileManager().addServiceListener(this);
@@ -218,6 +224,7 @@
         return mIsActive;
     }
 
+    @WorkerThread
     @Override
     public void setBluetoothEnabled(boolean enabled) {
         if (mLocalBluetoothManager != null) {
@@ -230,6 +237,7 @@
         return mLocalBluetoothManager != null;
     }
 
+    @WorkerThread
     @Override
     public String getConnectedDeviceName() {
         synchronized (mConnectedDevices) {
@@ -251,6 +259,7 @@
                 getDevices(), this::onConnectionStatusFetched);
     }
 
+    // Careful! This may be invoked in the main thread.
     private void onConnectionStatusFetched(ConnectionStatusModel status) {
         List<CachedBluetoothDevice> newList = status.getConnectedDevices();
         int state = status.getMaxConnectionState();
@@ -282,30 +291,33 @@
     }
 
     private void updateAudioProfile() {
-        boolean audioProfileConnected = false;
-        boolean otherProfileConnected = false;
+        // We want this in the background as calls inside `LocalBluetoothProfile` end up being
+        // binder calls
+        mBackgroundExecutor.execute(() -> {
+            boolean audioProfileConnected = false;
+            boolean otherProfileConnected = false;
 
-        for (CachedBluetoothDevice device : getDevices()) {
-            for (LocalBluetoothProfile profile : device.getProfiles()) {
-                int profileId = profile.getProfileId();
-                boolean isConnected = device.isConnectedProfile(profile);
-                if (profileId == BluetoothProfile.HEADSET
-                        || profileId == BluetoothProfile.A2DP
-                        || profileId == BluetoothProfile.HEARING_AID
-                        || profileId == BluetoothProfile.LE_AUDIO) {
-                    audioProfileConnected |= isConnected;
-                } else {
-                    otherProfileConnected |= isConnected;
+            for (CachedBluetoothDevice device : getDevices()) {
+                for (LocalBluetoothProfile profile : device.getProfiles()) {
+                    int profileId = profile.getProfileId();
+                    boolean isConnected = device.isConnectedProfile(profile);
+                    if (profileId == BluetoothProfile.HEADSET
+                            || profileId == BluetoothProfile.A2DP
+                            || profileId == BluetoothProfile.HEARING_AID
+                            || profileId == BluetoothProfile.LE_AUDIO) {
+                        audioProfileConnected |= isConnected;
+                    } else {
+                        otherProfileConnected |= isConnected;
+                    }
                 }
             }
-        }
 
-        boolean audioProfileOnly = (audioProfileConnected && !otherProfileConnected);
-        if (audioProfileOnly != mAudioProfileOnly) {
-            mAudioProfileOnly = audioProfileOnly;
-            mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
-        }
-
+            boolean audioProfileOnly = (audioProfileConnected && !otherProfileConnected);
+            if (audioProfileOnly != mAudioProfileOnly) {
+                mAudioProfileOnly = audioProfileOnly;
+                mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
+            }
+        });
     }
 
     @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/bluetooth/BluetoothRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepository.kt
index 80f3d76..96717c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepository.kt
@@ -38,7 +38,8 @@
     /**
      * Fetches the connection statuses for the given [currentDevices] and invokes [callback] once
      * those statuses have been fetched. The fetching occurs on a background thread because IPCs may
-     * be required to fetch the statuses (see b/271058380).
+     * be required to fetch the statuses (see b/271058380). However, the callback will be invoked in
+     * the main thread.
      */
     fun fetchConnectionStatusInBackground(
         currentDevices: Collection<CachedBluetoothDevice>,
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/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 760fe6a..f5edb7b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -42,6 +42,7 @@
      *   list, then list.get(i) could throw an IndexOutOfBoundsException. This method should not be
      *   used; try using `synchronized` or making a copy of the list instead.
      */
+    @Deprecated
     public static <T> void safeForeach(List<T> list, Consumer<T> c) {
         for (int i = list.size() - 1; i >= 0; i--) {
             T item = list.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/util/annotations/WeaklyReferencedCallback.java b/packages/SystemUI/src/com/android/systemui/util/annotations/WeaklyReferencedCallback.java
new file mode 100644
index 0000000..855bba6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/annotations/WeaklyReferencedCallback.java
@@ -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.util.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Descriptive annotation for clearly tagging callback types that are weakly
+ * referenced during registration.
+ *
+ * This is useful in providing hints to Proguard about certain fields that
+ * should be kept to preserve strong references.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({TYPE})
+public @interface WeaklyReferencedCallback {}
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/kotlin/Utils.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
index 73e2f97..ffbc10a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
@@ -19,6 +19,7 @@
 class Utils {
     companion object {
         fun <A, B, C> toTriple(a: A, bc: Pair<B, C>) = Triple(a, bc.first, bc.second)
+        fun <A, B, C> toTriple(ab: Pair<A, B>, c: C) = Triple(ab.first, ab.second, c)
 
         fun <A, B, C, D> toQuad(a: A, b: B, c: C, d: D) = Quad(a, b, c, d)
         fun <A, B, C, D> toQuad(a: A, bcd: Triple<B, C, D>) =
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
index 968dcc9..df5162a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
@@ -26,6 +26,7 @@
 
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.annotations.WeaklyReferencedCallback;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -64,6 +65,7 @@
      * An interface for listening to the connection status.
      * @param <T> The wrapper type.
      */
+    @WeaklyReferencedCallback
     public interface Callback<T> {
         /**
          * Invoked when the service has been successfully connected to.
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/Observer.java b/packages/SystemUI/src/com/android/systemui/util/service/Observer.java
index 7687432..425336d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/Observer.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/Observer.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.util.service;
 
+import com.android.systemui.util.annotations.WeaklyReferencedCallback;
+
 /**
  * The {@link Observer} interface specifies an entity which listeners
  * can be informed of changes to the source, which will require updating. Note that this deals
@@ -25,6 +27,7 @@
     /**
      * Callback for receiving updates from the {@link Observer}.
      */
+    @WeaklyReferencedCallback
     interface Callback {
         /**
          * Invoked when the source has changed.
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/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
index c1be44a..167e341 100644
--- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
+++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
@@ -81,7 +81,7 @@
     @get:Provides val notificationStackSizeCalculator: NotificationStackSizeCalculator = mock(),
     @get:Provides val notificationWakeUpCoordinator: NotificationWakeUpCoordinator = mock(),
     @get:Provides val screenLifecycle: ScreenLifecycle = mock(),
-    @get:Provides val screenOffAnimController: ScreenOffAnimationController = 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(),
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 62f9a9d..20d4eb9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -810,7 +810,6 @@
                     SceneKey.Bouncer,
                     flowOf(.5f),
                     false,
-                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
@@ -826,8 +825,7 @@
                     SceneKey.Bouncer,
                     SceneKey.Gone,
                     flowOf(.5f),
-                    false,
-                    isUserInputOngoing = flowOf(false),
+                    false
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
@@ -844,8 +842,7 @@
                     SceneKey.Gone,
                     SceneKey.Bouncer,
                     flowOf(.5f),
-                    false,
-                    isUserInputOngoing = flowOf(false),
+                    false
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
@@ -863,8 +860,7 @@
                     SceneKey.Bouncer,
                     SceneKey.Gone,
                     flowOf(.5f),
-                    false,
-                    isUserInputOngoing = flowOf(false),
+                    false
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
@@ -880,7 +876,6 @@
                     SceneKey.Lockscreen,
                     flowOf(.5f),
                     false,
-                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen, null), "reason")
@@ -898,7 +893,6 @@
                     SceneKey.Gone,
                     flowOf(.5f),
                     false,
-                    isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
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 9a908d7..948942f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -16,19 +16,24 @@
 
 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.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;
@@ -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)
@@ -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/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/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index e9e9624..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
@@ -45,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
@@ -141,7 +139,6 @@
     ) {
         controllerOverlay = UdfpsControllerOverlay(
             context,
-            fingerprintManager,
             inflater,
             windowManager,
             accessibilityManager,
@@ -155,7 +152,6 @@
             keyguardStateController,
             unlockedScreenOffAnimationController,
             udfpsDisplayMode,
-            secureSettings,
             REQUEST_ID,
             reason,
             controllerCallback,
@@ -165,7 +161,6 @@
             primaryBouncerInteractor,
             alternateBouncerInteractor,
             isDebuggable,
-            udfpsUtils,
             udfpsKeyguardAccessibilityDelegate,
             udfpsKeyguardViewModels,
         )
@@ -212,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)
         }
     }
 
@@ -230,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)
         }
     }
 
@@ -247,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)
         }
     }
 
@@ -264,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)
         }
     }
 
@@ -345,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(
@@ -363,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 a36f4e9..dcb5398 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -88,7 +88,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.ScreenLifecycle;
 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels;
@@ -105,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;
 
@@ -122,7 +120,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Optional;
 
 import javax.inject.Provider;
 
@@ -206,8 +203,6 @@
     @Mock
     private ActivityLaunchAnimator mActivityLaunchAnimator;
     @Mock
-    private AlternateUdfpsTouchProvider mAlternateTouchProvider;
-    @Mock
     private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     @Mock
     private SinglePointerTouchProcessor mSinglePointerTouchProcessor;
@@ -216,8 +211,6 @@
     @Mock
     private AlternateBouncerInteractor mAlternateBouncerInteractor;
     @Mock
-    private SecureSettings mSecureSettings;
-    @Mock
     private UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
     @Mock
     private Provider<UdfpsKeyguardViewModels> mUdfpsKeyguardViewModels;
@@ -239,7 +232,6 @@
     private ScreenLifecycle.Observer mScreenObserver;
     private FingerprintSensorPropertiesInternal mOpticalProps;
     private FingerprintSensorPropertiesInternal mUltrasonicProps;
-    private UdfpsUtils mUdfpsUtils;
     @Mock
     private InputManager mInputManager;
     @Mock
@@ -250,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))
@@ -292,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(),
@@ -339,15 +318,12 @@
                 mSystemUIDialogManager,
                 mLatencyTracker,
                 mActivityLaunchAnimator,
-                alternateTouchProvider,
                 mBiometricExecutor,
                 mPrimaryBouncerInteractor,
                 mSinglePointerTouchProcessor,
                 mSessionTracker,
                 mAlternateBouncerInteractor,
-                mSecureSettings,
                 mInputManager,
-                mUdfpsUtils,
                 mock(KeyguardFaceAuthInteractor.class),
                 mUdfpsKeyguardAccessibilityDelegate,
                 mUdfpsKeyguardViewModels
@@ -374,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();
@@ -408,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);
@@ -436,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();
@@ -593,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));
         }
     }
 
@@ -621,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,
@@ -654,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,
@@ -677,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,
@@ -700,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,
@@ -724,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
@@ -744,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) {
@@ -800,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);
@@ -834,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,
@@ -855,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
@@ -907,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);
@@ -918,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();
@@ -931,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();
@@ -1015,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);
@@ -1033,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();
@@ -1043,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) {
@@ -1122,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(
@@ -1159,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(
@@ -1187,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(
@@ -1221,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(
@@ -1308,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();
@@ -1402,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();
@@ -1453,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();
@@ -1491,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();
@@ -1531,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);
@@ -1564,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();
@@ -1578,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();
@@ -1689,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/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 b018a3e..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,15 +18,12 @@
 
 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;
@@ -44,8 +41,7 @@
         UdfpsKeyguardViewLegacyControllerBaseTest {
     @Override
     public UdfpsKeyguardViewControllerLegacy createUdfpsKeyguardViewController() {
-        return createUdfpsKeyguardViewController(/* useModernBouncer */ false,
-                /* useExpandedOverlay */ false);
+        return createUdfpsKeyguardViewController(/* useModernBouncer */ false);
     }
 
     @Test
@@ -216,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 da4548b..02ee53879 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -106,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/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
index 0c8e7a5..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
@@ -42,7 +40,6 @@
 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
@@ -80,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/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/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 41a8be9..33a6667 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
@@ -6,6 +6,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalHubSection
 import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalWidgetSection
 import org.junit.Before
 import org.junit.Test
@@ -18,6 +19,7 @@
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class DefaultCommunalBlueprintTest : SysuiTestCase() {
+    @Mock private lateinit var hubSection: DefaultCommunalHubSection
     @Mock private lateinit var widgetSection: DefaultCommunalWidgetSection
 
     private lateinit var blueprint: DefaultCommunalBlueprint
@@ -25,13 +27,14 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        blueprint = DefaultCommunalBlueprint(widgetSection)
+        blueprint = DefaultCommunalBlueprint(hubSection, widgetSection)
     }
 
     @Test
     fun addView() {
         val constraintLayout = ConstraintLayout(context, null)
         blueprint.replaceViews(null, constraintLayout)
+        verify(hubSection).addViews(constraintLayout)
         verify(widgetSection).addViews(constraintLayout)
     }
 
@@ -39,6 +42,7 @@
     fun applyConstraints() {
         val cs = ConstraintSet()
         blueprint.applyConstraints(cs)
+        verify(hubSection).applyConstraints(cs)
         verify(widgetSection).applyConstraints(cs)
     }
 }
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 679dfef..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
@@ -12,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
@@ -22,6 +23,7 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -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 c4cd8a4..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
@@ -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/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/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
index faf9751..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,13 +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.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
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 1e80fb6..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,8 +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.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
@@ -70,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/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 9ee22c8..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
@@ -204,8 +204,7 @@
                     fromScene = SceneKey.Gone,
                     toScene = SceneKey.Lockscreen,
                     progress = flowOf(0f),
-                    isInitiatedByUserInput = false,
-                    isUserInputOngoing = flowOf(false),
+                    isUserInputDriven = false,
                 )
             runCurrent()
             assertThat(isAnimate).isFalse()
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/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 2cf0e77..5d5ece0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -433,7 +433,9 @@
 
             // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
             runTransitionAndSetWakefulness(
-                    KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+                KeyguardState.GONE,
+                KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+            )
 
             // WHEN the lockscreen hosted dream stops
             keyguardRepository.setIsActiveDreamLockscreenHosted(false)
@@ -457,7 +459,9 @@
         testScope.runTest {
             // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
             runTransitionAndSetWakefulness(
-                    KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+                KeyguardState.GONE,
+                KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+            )
 
             // WHEN biometrics succeeds with wake and unlock from dream mode
             keyguardRepository.setBiometricUnlockState(
@@ -487,7 +491,9 @@
 
             // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
             runTransitionAndSetWakefulness(
-                    KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+                KeyguardState.GONE,
+                KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+            )
 
             // WHEN the primary bouncer is set to show
             bouncerRepository.setPrimaryShow(true)
@@ -515,7 +521,9 @@
 
             // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
             runTransitionAndSetWakefulness(
-                    KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+                KeyguardState.GONE,
+                KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+            )
 
             // WHEN the device begins to sleep
             keyguardRepository.setIsActiveDreamLockscreenHosted(false)
@@ -547,7 +555,9 @@
 
             // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
             runTransitionAndSetWakefulness(
-                    KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
+                KeyguardState.GONE,
+                KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+            )
 
             // WHEN the keyguard is occluded and the lockscreen hosted dream stops
             keyguardRepository.setIsActiveDreamLockscreenHosted(false)
@@ -783,7 +793,9 @@
         testScope.runTest {
             // GIVEN a prior transition has run to ALTERNATE_BOUNCER
             runTransitionAndSetWakefulness(
-                    KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
+                KeyguardState.LOCKSCREEN,
+                KeyguardState.ALTERNATE_BOUNCER
+            )
 
             // WHEN the alternateBouncer stops showing and then the primary bouncer shows
             bouncerRepository.setPrimaryShow(true)
@@ -808,7 +820,9 @@
             // GIVEN a prior transition has run to ALTERNATE_BOUNCER
             bouncerRepository.setAlternateVisible(true)
             runTransitionAndSetWakefulness(
-                    KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
+                KeyguardState.LOCKSCREEN,
+                KeyguardState.ALTERNATE_BOUNCER
+            )
 
             // GIVEN the primary bouncer isn't showing, aod available and starting to sleep
             bouncerRepository.setPrimaryShow(false)
@@ -838,7 +852,9 @@
             // GIVEN a prior transition has run to ALTERNATE_BOUNCER
             bouncerRepository.setAlternateVisible(true)
             runTransitionAndSetWakefulness(
-                    KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
+                KeyguardState.LOCKSCREEN,
+                KeyguardState.ALTERNATE_BOUNCER
+            )
 
             // GIVEN the primary bouncer isn't showing, aod not available and starting to sleep
             // to sleep
@@ -869,7 +885,9 @@
             // GIVEN a prior transition has run to ALTERNATE_BOUNCER
             bouncerRepository.setAlternateVisible(true)
             runTransitionAndSetWakefulness(
-                    KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
+                KeyguardState.LOCKSCREEN,
+                KeyguardState.ALTERNATE_BOUNCER
+            )
 
             // GIVEN the primary bouncer isn't showing and device not sleeping
             bouncerRepository.setPrimaryShow(false)
@@ -980,7 +998,9 @@
             // GIVEN a prior transition has run to PRIMARY_BOUNCER
             bouncerRepository.setPrimaryShow(true)
             runTransitionAndSetWakefulness(
-                    KeyguardState.DREAMING_LOCKSCREEN_HOSTED, KeyguardState.PRIMARY_BOUNCER)
+                KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+                KeyguardState.PRIMARY_BOUNCER
+            )
 
             // WHEN the primary bouncer stops showing and lockscreen hosted dream still active
             bouncerRepository.setPrimaryShow(false)
@@ -1161,6 +1181,57 @@
         }
 
     @Test
+    fun dreamingToOccluded() =
+        testScope.runTest {
+            // GIVEN a prior transition has run to DREAMING
+            keyguardRepository.setDreaming(true)
+            runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DREAMING)
+            runCurrent()
+
+            // WHEN the keyguard is occluded and device wakes up and is no longer dreaming
+            keyguardRepository.setDreaming(false)
+            keyguardRepository.setKeyguardOccluded(true)
+            powerInteractor.setAwakeForTest()
+            runCurrent()
+
+            val info =
+                withArgCaptor<TransitionInfo> {
+                    verify(transitionRepository).startTransition(capture(), anyBoolean())
+                }
+            // THEN a transition to OCCLUDED should occur
+            assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
+            assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
+            assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
+            assertThat(info.animator).isNotNull()
+
+            coroutineContext.cancelChildren()
+        }
+
+    @Test
+    fun lockscreenToOccluded() =
+        testScope.runTest {
+            // GIVEN a prior transition has run to LOCKSCREEN
+            runTransitionAndSetWakefulness(KeyguardState.GONE, KeyguardState.LOCKSCREEN)
+            runCurrent()
+
+            // WHEN the keyguard is occluded
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+
+            val info =
+                withArgCaptor<TransitionInfo> {
+                    verify(transitionRepository).startTransition(capture(), anyBoolean())
+                }
+            // THEN a transition to OCCLUDED should occur
+            assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
+            assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
+            assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED)
+            assertThat(info.animator).isNotNull()
+
+            coroutineContext.cancelChildren()
+        }
+
+    @Test
     fun aodToOccluded() =
         testScope.runTest {
             // GIVEN a prior transition has run to AOD
@@ -1286,8 +1357,8 @@
     }
 
     private suspend fun TestScope.runTransitionAndSetWakefulness(
-            from: KeyguardState,
-            to: KeyguardState
+        from: KeyguardState,
+        to: KeyguardState
     ) {
         transitionRepository.sendTransitionStep(
             TransitionStep(
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/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index 9364097..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
@@ -60,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/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/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
index 85d3fba..deefab6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
@@ -21,6 +21,7 @@
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
 import android.graphics.drawable.Drawable
+import android.media.MediaRoute2Info
 import android.media.MediaRouter2Manager
 import android.media.RoutingSessionInfo
 import android.media.session.MediaController
@@ -34,15 +35,18 @@
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
 import com.android.settingslib.media.LocalMediaManager
 import com.android.settingslib.media.MediaDevice
-import com.android.systemui.res.R
+import com.android.settingslib.media.PhoneMediaDevice
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
 import com.android.systemui.media.controls.MediaTestUtils
 import com.android.systemui.media.controls.models.player.MediaData
 import com.android.systemui.media.controls.models.player.MediaDeviceData
 import com.android.systemui.media.controls.util.MediaControllerFactory
 import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager
 import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManagerFactory
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.eq
@@ -95,6 +99,7 @@
     @Mock private lateinit var device: MediaDevice
     @Mock private lateinit var icon: Drawable
     @Mock private lateinit var route: RoutingSessionInfo
+    @Mock private lateinit var selectedRoute: MediaRoute2Info
     @Mock private lateinit var controller: MediaController
     @Mock private lateinit var playbackInfo: PlaybackInfo
     @Mock private lateinit var configurationController: ConfigurationController
@@ -107,6 +112,7 @@
     private lateinit var session: MediaSession
     private lateinit var mediaData: MediaData
     @JvmField @Rule val mockito = MockitoJUnit.rule()
+    private val featureFlags = FakeFeatureFlagsClassic()
 
     @Before
     fun setUp() {
@@ -124,7 +130,8 @@
                 localBluetoothManager,
                 fakeFgExecutor,
                 fakeBgExecutor,
-                dumpster
+                dumpster,
+                featureFlags,
             )
         manager.addListener(listener)
 
@@ -143,6 +150,7 @@
             MediaTestUtils.emptyMediaData.copy(packageName = PACKAGE, token = session.sessionToken)
         whenever(controllerFactory.create(session.sessionToken)).thenReturn(controller)
         setupLeAudioConfiguration(false)
+        featureFlags.set(Flags.MEDIA_DEVICE_NAME_FIX, false)
     }
 
     @After
@@ -454,9 +462,54 @@
     }
 
     @Test
-    fun mr2ReturnsRouteWithNullName_useLocalDeviceName() {
+    fun mr2ReturnsSystemRouteWithNullName_isPhone_usePhoneName() {
+        featureFlags.set(Flags.MEDIA_DEVICE_NAME_FIX, true)
+        // When the routing session name is null, and is a system session for a PhoneMediaDevice
+        val phoneDevice = mock(PhoneMediaDevice::class.java)
+        whenever(phoneDevice.iconWithoutBackground).thenReturn(icon)
+        whenever(lmm.currentConnectedDevice).thenReturn(phoneDevice)
+        whenever(route.isSystemSession).thenReturn(true)
+
+        whenever(route.name).thenReturn(null)
+        whenever(mr2.getSelectedRoutes(any())).thenReturn(listOf(selectedRoute))
+        whenever(selectedRoute.name).thenReturn(REMOTE_DEVICE_NAME)
+        whenever(selectedRoute.type).thenReturn(MediaRoute2Info.TYPE_BUILTIN_SPEAKER)
+
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+
+        // Then the device name is the PhoneMediaDevice string
+        val data = captureDeviceData(KEY)
+        assertThat(data.name)
+            .isEqualTo(
+                context.getString(com.android.settingslib.R.string.media_transfer_this_device_name)
+            )
+    }
+
+    @Test
+    fun mr2ReturnsSystemRouteWithNullName_useSelectedRouteName() {
+        featureFlags.set(Flags.MEDIA_DEVICE_NAME_FIX, true)
+        // When the routing session does not have a name, and is a system session
+        whenever(route.name).thenReturn(null)
+        whenever(mr2.getSelectedRoutes(any())).thenReturn(listOf(selectedRoute))
+        whenever(selectedRoute.name).thenReturn(REMOTE_DEVICE_NAME)
+        whenever(route.isSystemSession).thenReturn(true)
+
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+
+        // Then the device name is the selected route name
+        val data = captureDeviceData(KEY)
+        assertThat(data.name).isEqualTo(REMOTE_DEVICE_NAME)
+    }
+
+    @Test
+    fun mr2ReturnsNonSystemRouteWithNullName_useLocalDeviceName() {
         // GIVEN that MR2Manager returns a routing session that does not have a name
         whenever(route.name).thenReturn(null)
+        whenever(route.isSystemSession).thenReturn(false)
         // WHEN a notification is added
         manager.onMediaDataLoaded(KEY, null, mediaData)
         fakeBgExecutor.runAllReady()
@@ -672,13 +725,108 @@
         assertThat(data.showBroadcastButton).isFalse()
     }
 
-    fun captureCallback(): LocalMediaManager.DeviceCallback {
+    // Duplicates of above tests with MEDIA_DEVICE_NAME_FIX enabled
+
+    @Test
+    fun loadMediaDataWithNullToken_withNameFix() {
+        featureFlags.set(Flags.MEDIA_DEVICE_NAME_FIX, true)
+        manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null))
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        val data = captureDeviceData(KEY)
+        assertThat(data.enabled).isTrue()
+        assertThat(data.name).isEqualTo(DEVICE_NAME)
+    }
+
+    @Test
+    fun onAboutToConnectDeviceAdded_findsDeviceInfoFromAddress_withNameFix() {
+        featureFlags.set(Flags.MEDIA_DEVICE_NAME_FIX, true)
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        // Run and reset the executors and listeners so we only focus on new events.
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        reset(listener)
+
+        // Ensure we'll get device info when using the address
+        val fullMediaDevice = mock(MediaDevice::class.java)
+        val address = "fakeAddress"
+        val nameFromDevice = "nameFromDevice"
+        val iconFromDevice = mock(Drawable::class.java)
+        whenever(lmm.getMediaDeviceById(eq(address))).thenReturn(fullMediaDevice)
+        whenever(fullMediaDevice.name).thenReturn(nameFromDevice)
+        whenever(fullMediaDevice.iconWithoutBackground).thenReturn(iconFromDevice)
+
+        // WHEN the about-to-connect device changes to non-null
+        val deviceCallback = captureCallback()
+        val nameFromParam = "nameFromParam"
+        val iconFromParam = mock(Drawable::class.java)
+        deviceCallback.onAboutToConnectDeviceAdded(address, nameFromParam, iconFromParam)
+        assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1)
+
+        // THEN the about-to-connect device based on the address is returned
+        val data = captureDeviceData(KEY)
+        assertThat(data.enabled).isTrue()
+        assertThat(data.name).isEqualTo(nameFromDevice)
+        assertThat(data.name).isNotEqualTo(nameFromParam)
+        assertThat(data.icon).isEqualTo(iconFromDevice)
+        assertThat(data.icon).isNotEqualTo(iconFromParam)
+    }
+
+    @Test
+    fun deviceNameFromMR2RouteInfo_withNameFix() {
+        featureFlags.set(Flags.MEDIA_DEVICE_NAME_FIX, true)
+        // GIVEN that MR2Manager returns a valid routing session
+        whenever(route.name).thenReturn(REMOTE_DEVICE_NAME)
+        // WHEN a notification is added
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        // THEN it uses the route name (instead of device name)
+        val data = captureDeviceData(KEY)
+        assertThat(data.enabled).isTrue()
+        assertThat(data.name).isEqualTo(REMOTE_DEVICE_NAME)
+    }
+
+    @Test
+    fun deviceDisabledWhenMR2ReturnsNullRouteInfo_withNameFix() {
+        featureFlags.set(Flags.MEDIA_DEVICE_NAME_FIX, true)
+        // GIVEN that MR2Manager returns null for routing session
+        whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
+        // WHEN a notification is added
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        // THEN the device is disabled and name is set to null
+        val data = captureDeviceData(KEY)
+        assertThat(data.enabled).isFalse()
+        assertThat(data.name).isNull()
+    }
+
+    @Test
+    fun mr2ReturnsNonSystemRouteWithNullName_useLocalDeviceName_withNameFix() {
+        featureFlags.set(Flags.MEDIA_DEVICE_NAME_FIX, true)
+        // GIVEN that MR2Manager returns a routing session that does not have a name
+        whenever(route.name).thenReturn(null)
+        whenever(route.isSystemSession).thenReturn(false)
+        // WHEN a notification is added
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        // THEN the device is enabled and uses the current connected device name
+        val data = captureDeviceData(KEY)
+        assertThat(data.name).isEqualTo(DEVICE_NAME)
+        assertThat(data.enabled).isTrue()
+    }
+
+    // End duplicate tests
+
+    private fun captureCallback(): LocalMediaManager.DeviceCallback {
         val captor = ArgumentCaptor.forClass(LocalMediaManager.DeviceCallback::class.java)
         verify(lmm).registerCallback(captor.capture())
         return captor.getValue()
     }
 
-    fun setupBroadcastCallback(): BluetoothLeBroadcast.Callback {
+    private fun setupBroadcastCallback(): BluetoothLeBroadcast.Callback {
         val callback: BluetoothLeBroadcast.Callback =
             object : BluetoothLeBroadcast.Callback {
                 override fun onBroadcastStarted(reason: Int, broadcastId: Int) {}
@@ -699,7 +847,7 @@
         return callback
     }
 
-    fun setupLeAudioConfiguration(isLeAudio: Boolean) {
+    private fun setupLeAudioConfiguration(isLeAudio: Boolean) {
         whenever(localBluetoothManager.profileManager).thenReturn(localBluetoothProfileManager)
         whenever(localBluetoothProfileManager.leAudioBroadcastProfile)
             .thenReturn(localBluetoothLeBroadcast)
@@ -707,7 +855,7 @@
         whenever(localBluetoothLeBroadcast.appSourceName).thenReturn(BROADCAST_APP_NAME)
     }
 
-    fun setupBroadcastPackage(currentName: String) {
+    private fun setupBroadcastPackage(currentName: String) {
         whenever(lmm.packageName).thenReturn(PACKAGE)
         whenever(packageManager.getApplicationInfo(eq(PACKAGE), anyInt()))
             .thenReturn(applicationInfo)
@@ -715,7 +863,7 @@
         context.setMockPackageManager(packageManager)
     }
 
-    fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData {
+    private fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData {
         val captor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
         verify(listener).onMediaDeviceChanged(eq(key), eq(oldKey), captor.capture())
         return captor.getValue()
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/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
index f25cd24..34360d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
@@ -7,12 +7,16 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
+import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver
+import com.android.systemui.shared.recents.model.ThumbnailData
 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 kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -34,6 +38,8 @@
     private val view: MediaProjectionAppSelectorView = mock()
     private val policyResolver: ScreenCaptureDevicePolicyResolver = mock()
 
+    private val thumbnailLoader = FakeThumbnailLoader()
+
     private val controller =
         MediaProjectionAppSelectorController(
             taskListProvider,
@@ -42,7 +48,8 @@
             personalUserHandle,
             scope,
             appSelectorComponentName,
-            callerPackageName
+            callerPackageName,
+            thumbnailLoader,
         )
 
     @Before
@@ -69,6 +76,22 @@
     }
 
     @Test
+    fun init_refreshesThumbnailsOfForegroundTasks() = runTest {
+        val tasks =
+            listOf(
+                createRecentTask(taskId = 1, isForegroundTask = false),
+                createRecentTask(taskId = 2, isForegroundTask = true),
+                createRecentTask(taskId = 3, isForegroundTask = true),
+                createRecentTask(taskId = 4, isForegroundTask = false),
+            )
+        taskListProvider.tasks = tasks
+
+        controller.init()
+
+        assertThat(thumbnailLoader.capturedTaskIds).containsExactly(2, 3)
+    }
+
+    @Test
     fun initMultipleRecentTasksWithoutAppSelectorTask_bindsListInTheSameOrder() {
         val tasks =
             listOf(
@@ -188,14 +211,16 @@
     private fun createRecentTask(
         taskId: Int,
         topActivityComponent: ComponentName? = null,
-        userId: Int = personalUserHandle.identifier
+        userId: Int = personalUserHandle.identifier,
+        isForegroundTask: Boolean = false
     ): RecentTask {
         return RecentTask(
             taskId = taskId,
             topActivityComponent = topActivityComponent,
             baseIntentComponent = ComponentName("com", "Test"),
             userId = userId,
-            colorBackground = 0
+            colorBackground = 0,
+            isForegroundTask = isForegroundTask,
         )
     }
 
@@ -205,4 +230,18 @@
 
         override suspend fun loadRecentTasks(): List<RecentTask> = tasks
     }
+
+    private class FakeThumbnailLoader : RecentTaskThumbnailLoader {
+
+        val capturedTaskIds = mutableListOf<Int>()
+
+        override suspend fun loadThumbnail(taskId: Int): ThumbnailData? {
+            return null
+        }
+
+        override suspend fun captureThumbnail(taskId: Int): ThumbnailData? {
+            capturedTaskIds += taskId
+            return null
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
new file mode 100644
index 0000000..db275ec
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
@@ -0,0 +1,109 @@
+package com.android.systemui.mediaprojection.appselector.data
+
+import android.app.WindowConfiguration
+import android.content.ComponentName
+import android.content.res.Configuration
+import android.graphics.ColorSpace
+import android.graphics.Point
+import android.graphics.Rect
+import android.hardware.HardwareBuffer
+import android.testing.AndroidTestingRunner
+import android.view.Surface
+import android.window.TaskSnapshot
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+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.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class ActivityTaskManagerThumbnailLoaderTest : SysuiTestCase() {
+
+    private val dispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(dispatcher)
+    private val activityManager = mock<ActivityManagerWrapper>()
+    private val loader = ActivityTaskManagerThumbnailLoader(dispatcher, activityManager)
+
+    @Test
+    fun loadThumbnail_emptyThumbnail_returnsNull() =
+        testScope.runTest {
+            val taskId = 123
+            val isLowResolution = false
+            val thumbnailData = ThumbnailData()
+            whenever(activityManager.getTaskThumbnail(taskId, isLowResolution))
+                .thenReturn(thumbnailData)
+
+            assertThat(loader.loadThumbnail(taskId)).isNull()
+        }
+
+    @Test
+    fun loadThumbnail_thumbnailAvailable_returnsThumbnailData() =
+        testScope.runTest {
+            val taskId = 123
+            val isLowResolution = false
+            val snapshot = createTaskSnapshot()
+            val thumbnailData = ThumbnailData(snapshot)
+            whenever(activityManager.getTaskThumbnail(taskId, isLowResolution))
+                .thenReturn(thumbnailData)
+
+            assertThat(loader.loadThumbnail(taskId)).isEqualTo(thumbnailData)
+        }
+
+    @Test
+    fun captureThumbnail_emptyThumbnail_returnsNull() =
+        testScope.runTest {
+            val taskId = 321
+            val emptyThumbnailData = ThumbnailData()
+
+            whenever(activityManager.takeTaskThumbnail(taskId)).thenReturn(emptyThumbnailData)
+
+            assertThat(loader.captureThumbnail(taskId)).isNull()
+        }
+
+    @Test
+    fun captureThumbnail_thumbnailAvailable_returnsThumbnailData() =
+        testScope.runTest {
+            val taskId = 321
+            val thumbnailData = ThumbnailData(createTaskSnapshot())
+
+            whenever(activityManager.takeTaskThumbnail(taskId)).thenReturn(thumbnailData)
+
+            assertThat(loader.captureThumbnail(taskId)).isEqualTo(thumbnailData)
+        }
+
+    private fun createTaskSnapshot() =
+        TaskSnapshot(
+            /* id= */ 123,
+            /* captureTime= */ 0,
+            /* topActivityComponent= */ ComponentName("package", "class"),
+            /* snapshot= */ HardwareBuffer.create(
+                /* width= */ 100,
+                /* height= */ 100,
+                HardwareBuffer.RGBA_8888,
+                /* layers= */ 1,
+                /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN
+            ),
+            ColorSpace.get(ColorSpace.Named.SRGB),
+            Configuration.ORIENTATION_PORTRAIT,
+            Surface.ROTATION_0,
+            /* taskSize= */ Point(100, 100),
+            /* contentInsets= */ Rect(),
+            /* letterboxInsets= */ Rect(),
+            /* isLowResolution= */ false,
+            /* isRealSnapshot= */ true,
+            WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+            /* appearance= */ 0,
+            /* isTranslucent= */ false,
+            /* hasImeSurface= */ false
+        )
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
index d35a212..2c7ee56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
@@ -11,7 +11,7 @@
 import com.android.wm.shell.recents.RecentTasks
 import com.android.wm.shell.util.GroupedRecentTaskInfo
 import com.google.common.truth.Truth.assertThat
-import java.util.*
+import java.util.Optional
 import java.util.function.Consumer
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
@@ -52,12 +52,7 @@
 
         val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
 
-        assertThat(result)
-            .containsExactly(
-                createRecentTask(taskId = 1),
-                createRecentTask(taskId = 2),
-                createRecentTask(taskId = 3),
-            )
+        assertThat(result.map { it.taskId }).containsExactly(1, 2, 3).inOrder()
     }
 
     @Test
@@ -66,8 +61,7 @@
 
         val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
 
-        assertThat(result)
-            .containsExactly(createRecentTask(taskId = 1), createRecentTask(taskId = 2))
+        assertThat(result.map { it.taskId }).containsExactly(1, 2).inOrder()
     }
 
     @Test
@@ -81,15 +75,46 @@
 
         val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
 
-        assertThat(result)
-            .containsExactly(
-                createRecentTask(taskId = 1),
-                createRecentTask(taskId = 2),
-                createRecentTask(taskId = 3),
-                createRecentTask(taskId = 4),
-                createRecentTask(taskId = 5),
-                createRecentTask(taskId = 6),
-            )
+        assertThat(result.map { it.taskId }).containsExactly(1, 2, 3, 4, 5, 6).inOrder()
+    }
+
+    @Test
+    fun loadRecentTasks_singleTask_returnsTaskAsNotForeground() {
+        givenRecentTasks(
+            createSingleTask(taskId = 1),
+        )
+
+        val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
+
+        assertThat(result[0].isForegroundTask).isFalse()
+    }
+
+    @Test
+    fun loadRecentTasks_multipleTasks_returnsSecondTaskAsForegroundTask() {
+        givenRecentTasks(
+            createSingleTask(taskId = 1),
+            createSingleTask(taskId = 2),
+            createSingleTask(taskId = 3),
+        )
+
+        val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
+
+        assertThat(result.map { it.isForegroundTask }).containsExactly(false, true, false).inOrder()
+    }
+
+    @Test
+    fun loadRecentTasks_secondTaskIsGrouped_marksBothGroupedTasksAsForeground() {
+        givenRecentTasks(
+            createSingleTask(taskId = 1),
+            createTaskPair(taskId1 = 2, taskId2 = 3),
+            createSingleTask(taskId = 4),
+        )
+
+        val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
+
+        assertThat(result.map { it.isForegroundTask })
+            .containsExactly(false, true, true, false)
+            .inOrder()
     }
 
     @Suppress("UNCHECKED_CAST")
@@ -106,7 +131,8 @@
             userId = 0,
             topActivityComponent = null,
             baseIntentComponent = null,
-            colorBackground = null
+            colorBackground = null,
+            isForegroundTask = false,
         )
 
     private fun createSingleTask(taskId: Int): GroupedRecentTaskInfo =
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/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 4ada44c..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
@@ -25,7 +25,6 @@
 import androidx.test.filters.SmallTest
 import com.android.settingslib.Utils
 import com.android.settingslib.drawable.UserIconDrawable
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.common.shared.model.ContentDescription
@@ -35,6 +34,7 @@
 import com.android.systemui.qs.QSSecurityFooterUtils
 import com.android.systemui.qs.footer.FooterActionsTestUtils
 import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
+import com.android.systemui.res.R
 import com.android.systemui.security.data.model.SecurityModel
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.statusbar.policy.FakeSecurityController
@@ -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)
@@ -372,9 +367,7 @@
                     ),
             )
 
-        val job = launch {
-            underTest.observeDeviceMonitoringDialogRequests(quickSettingsContext = mock())
-        }
+        val job = launch { underTest.observeDeviceMonitoringDialogRequests(mock()) }
 
         advanceUntilIdle()
         assertThat(nDialogRequests).isEqualTo(3)
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/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 2e16577..61dd69a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -52,7 +52,6 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -463,8 +462,7 @@
                 fromScene = getCurrentSceneInUi(),
                 toScene = to.key,
                 progress = progressFlow,
-                isInitiatedByUserInput = false,
-                isUserInputOngoing = flowOf(false),
+                isUserInputDriven = false,
             )
         runCurrent()
 
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 740c6d9..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
@@ -29,7 +29,6 @@
 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
@@ -120,8 +119,7 @@
                     fromScene = SceneKey.Lockscreen,
                     toScene = SceneKey.Shade,
                     progress = progress,
-                    isInitiatedByUserInput = false,
-                    isUserInputOngoing = flowOf(false),
+                    isUserInputDriven = false,
                 )
             assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
 
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 31d26c0..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
@@ -83,8 +83,7 @@
                     fromScene = SceneKey.Lockscreen,
                     toScene = SceneKey.Shade,
                     progress = progress,
-                    isInitiatedByUserInput = false,
-                    isUserInputOngoing = flowOf(false),
+                    isUserInputDriven = false,
                 )
             assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
 
@@ -122,8 +121,7 @@
                     fromScene = underTest.desiredScene.value.key,
                     toScene = SceneKey.Shade,
                     progress = progress,
-                    isInitiatedByUserInput = false,
-                    isUserInputOngoing = flowOf(false),
+                    isUserInputDriven = false,
                 )
             assertThat(transitionTo).isEqualTo(SceneKey.Shade)
 
@@ -160,8 +158,7 @@
                         fromScene = SceneKey.Gone,
                         toScene = SceneKey.Lockscreen,
                         progress = flowOf(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             val transitioning by
@@ -180,8 +177,7 @@
                         fromScene = SceneKey.Shade,
                         toScene = SceneKey.QuickSettings,
                         progress = flowOf(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             underTest.setTransitionState(transitionState)
@@ -198,8 +194,7 @@
                         fromScene = SceneKey.Shade,
                         toScene = SceneKey.Lockscreen,
                         progress = flowOf(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             val transitioning by
@@ -227,8 +222,7 @@
                     fromScene = SceneKey.Shade,
                     toScene = SceneKey.Lockscreen,
                     progress = flowOf(0.5f),
-                    isInitiatedByUserInput = false,
-                    isUserInputOngoing = flowOf(false),
+                    isUserInputDriven = false,
                 )
             assertThat(transitioning).isTrue()
 
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 3b9621e..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
@@ -109,8 +109,7 @@
                     fromScene = SceneKey.Gone,
                     toScene = SceneKey.Shade,
                     progress = flowOf(0.5f),
-                    isInitiatedByUserInput = false,
-                    isUserInputOngoing = flowOf(false),
+                    isUserInputDriven = false,
                 )
             assertThat(isVisible).isTrue()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
@@ -123,8 +122,7 @@
                     fromScene = SceneKey.Shade,
                     toScene = SceneKey.Gone,
                     progress = flowOf(0.5f),
-                    isInitiatedByUserInput = false,
-                    isUserInputOngoing = flowOf(false),
+                    isUserInputDriven = false,
                 )
             assertThat(isVisible).isTrue()
             sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
index a105c15..d8821aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
@@ -63,8 +63,8 @@
 
     @Before
     fun setUp() {
-        whenever(controllerFactory.create(eq(0))).thenReturn(controller0)
-        whenever(controllerFactory.create(eq(1))).thenReturn(controller1)
+        whenever(controllerFactory.create(eq(0), any())).thenReturn(controller0)
+        whenever(controllerFactory.create(eq(1), any())).thenReturn(controller1)
     }
 
     @Test
@@ -74,8 +74,8 @@
             val onSaved = { _: Uri -> }
             screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback)
 
-            verify(controllerFactory).create(eq(0))
-            verify(controllerFactory).create(eq(1))
+            verify(controllerFactory).create(eq(0), any())
+            verify(controllerFactory).create(eq(1), any())
 
             val capturer = ArgumentCaptor<ScreenshotData>()
 
@@ -107,8 +107,8 @@
                 callback
             )
 
-            verify(controllerFactory).create(eq(0))
-            verify(controllerFactory, never()).create(eq(1))
+            verify(controllerFactory).create(eq(0), any())
+            verify(controllerFactory, never()).create(eq(1), any())
 
             val capturer = ArgumentCaptor<ScreenshotData>()
 
@@ -139,7 +139,7 @@
     @Test
     fun executeScreenshots_allowedTypes_allCaptured() =
         testScope.runTest {
-            whenever(controllerFactory.create(any())).thenReturn(controller0)
+            whenever(controllerFactory.create(any(), any())).thenReturn(controller0)
 
             setDisplays(
                 display(TYPE_INTERNAL, id = 0),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index 6205d90..5091a70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -86,7 +86,7 @@
             )
             .thenReturn(false)
         whenever(userManager.isUserUnlocked).thenReturn(true)
-        whenever(controllerFactory.create(any())).thenReturn(controller)
+        whenever(controllerFactory.create(any(), any())).thenReturn(controller)
 
         // Stub request processor as a synchronous no-op for tests with the flag enabled
         doAnswer {
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 b4f9e8d..677d9db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -49,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
@@ -144,7 +144,7 @@
     @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()
@@ -251,7 +251,7 @@
                     securityModel = mock(KeyguardSecurityModel::class.java),
                 ),
                 BouncerLogger(logcatLogBuffer("BouncerLog")),
-                keyEventInteractor,
+                sysUIKeyEventHandler,
                 primaryBouncerInteractor,
                 alternateBouncerInteractor,
             )
@@ -475,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 189c9e2..a4a2ca0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -48,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
@@ -253,7 +253,7 @@
                     securityModel = Mockito.mock(KeyguardSecurityModel::class.java),
                 ),
                 BouncerLogger(logcatLogBuffer("BouncerLog")),
-                Mockito.mock(KeyEventInteractor::class.java),
+                Mockito.mock(SysUIKeyEventHandler::class.java),
                 primaryBouncerInteractor,
                 alternateBouncerInteractor,
             )
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 bcb060d..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
@@ -60,7 +60,6 @@
 import dagger.Component
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -595,8 +594,7 @@
                         fromScene = SceneKey.Lockscreen,
                         toScene = key,
                         progress = progress,
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -633,8 +631,7 @@
                         fromScene = key,
                         toScene = SceneKey.Lockscreen,
                         progress = progress,
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -670,8 +667,7 @@
                         fromScene = SceneKey.Lockscreen,
                         toScene = SceneKey.Shade,
                         progress = progress,
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -947,8 +943,7 @@
                         fromScene = SceneKey.Lockscreen,
                         toScene = key,
                         progress = progress,
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -985,8 +980,7 @@
                         fromScene = SceneKey.Lockscreen,
                         toScene = key,
                         progress = progress,
-                        isInitiatedByUserInput = true,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = true,
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -1023,8 +1017,7 @@
                         fromScene = key,
                         toScene = SceneKey.Lockscreen,
                         progress = progress,
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -1061,8 +1054,7 @@
                         fromScene = key,
                         toScene = SceneKey.Lockscreen,
                         progress = progress,
-                        isInitiatedByUserInput = true,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = true,
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
@@ -1097,9 +1089,8 @@
                     ObservableTransitionState.Transition(
                         fromScene = SceneKey.Lockscreen,
                         toScene = SceneKey.QuickSettings,
-                        progress = MutableStateFlow(0f),
-                        isInitiatedByUserInput = true,
-                        isUserInputOngoing = flowOf(false),
+                        progress = progress,
+                        isUserInputDriven = true,
                     )
                 )
             sceneInteractor.setTransitionState(transitionState)
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 bb20d94..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
@@ -17,7 +17,6 @@
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -85,8 +84,7 @@
                         fromScene = SceneKey.Shade,
                         toScene = SceneKey.QuickSettings,
                         progress = MutableStateFlow(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             )
@@ -104,8 +102,7 @@
                         fromScene = SceneKey.QuickSettings,
                         toScene = SceneKey.Shade,
                         progress = MutableStateFlow(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             )
@@ -123,8 +120,7 @@
                         fromScene = SceneKey.Gone,
                         toScene = SceneKey.Shade,
                         progress = MutableStateFlow(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
+                        isUserInputDriven = false,
                     )
                 )
             )
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
index 99c3b19..31efebb 100644
--- 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
@@ -25,6 +25,7 @@
 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
@@ -37,10 +38,13 @@
 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
@@ -59,19 +63,24 @@
 class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Mock private lateinit var dozeParams: DozeParameters
+    @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController
 
     private lateinit var testComponent: TestComponent
-    private val underTest
+    private val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
         get() = testComponent.underTest
-    private val deviceProvisioningRepository
+    private val deviceEntryRepository: FakeDeviceEntryRepository
+        get() = testComponent.deviceEntryRepository
+    private val deviceProvisioningRepository: FakeDeviceProvisioningRepository
         get() = testComponent.deviceProvisioningRepository
-    private val keyguardRepository
+    private val keyguardRepository: FakeKeyguardRepository
         get() = testComponent.keyguardRepository
-    private val keyguardTransitionRepository
+    private val keyguardTransitionRepository: FakeKeyguardTransitionRepository
         get() = testComponent.keyguardTransitionRepository
-    private val powerRepository
+    private val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository
+        get() = testComponent.notifsKeyguardRepository
+    private val powerRepository: FakePowerRepository
         get() = testComponent.powerRepository
-    private val scope
+    private val scope: TestScope
         get() = testComponent.scope
 
     @Before
@@ -84,12 +93,14 @@
                     test = this,
                     featureFlags =
                         FakeFeatureFlagsClassicModule {
-                            set(Flags.FACE_AUTH_REFACTOR, value = false)
+                            setDefault(Flags.FACE_AUTH_REFACTOR)
                             set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+                            setDefault(Flags.NEW_AOD_TRANSITION)
                         },
                     mocks =
                         TestMocksModule(
                             dozeParameters = dozeParams,
+                            screenOffAnimationController = screenOffAnimController,
                         ),
                 )
 
@@ -251,6 +262,204 @@
             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 =
@@ -264,9 +473,11 @@
 
         val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
 
+        val deviceEntryRepository: FakeDeviceEntryRepository
         val deviceProvisioningRepository: FakeDeviceProvisioningRepository
         val keyguardRepository: FakeKeyguardRepository
         val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository
         val powerRepository: FakePowerRepository
         val scope: TestScope
 
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
index d1518f7..e1e7f92 100644
--- 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
@@ -82,6 +82,7 @@
             DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
                 .create(
                     test = this,
+                    // Configurable bindings
                     featureFlags =
                         FakeFeatureFlagsClassicModule {
                             set(Flags.FACE_AUTH_REFACTOR, value = false)
@@ -248,6 +249,7 @@
         modules =
             [
                 SysUITestModule::class,
+                // Real impls
                 BiometricsDomainLayerModule::class,
                 UserDomainLayerModule::class,
             ]
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/logging/StackStateLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt
deleted file mode 100644
index 47c5e5b..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt
+++ /dev/null
@@ -1,77 +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.systemui.statusbar.notification.logging
-
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogcatEchoTracker
-import com.android.systemui.log.core.LogLevel
-import com.android.systemui.statusbar.notification.stack.StackStateLogger
-import com.google.common.truth.Truth
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-class StackStateLoggerTest : SysuiTestCase() {
-    private val logBufferCounter = LogBufferCounter()
-    private lateinit var logger: StackStateLogger
-
-    @Before
-    fun setup() {
-        logger = StackStateLogger(logBufferCounter.logBuffer, logBufferCounter.logBuffer)
-    }
-
-    @Test
-    fun groupChildRemovalEvent() {
-        logger.groupChildRemovalEventProcessed(KEY)
-        verifyDidLog(1)
-        logger.groupChildRemovalAnimationEnded(KEY)
-        verifyDidLog(1)
-    }
-
-    class LogBufferCounter {
-        val recentLogs = mutableListOf<Pair<String, LogLevel>>()
-        val tracker =
-            object : LogcatEchoTracker {
-                override val logInBackgroundThread: Boolean = false
-                override fun isBufferLoggable(bufferName: String, level: LogLevel): Boolean = false
-                override fun isTagLoggable(tagName: String, level: LogLevel): Boolean {
-                    recentLogs.add(tagName to level)
-                    return true
-                }
-            }
-        val logBuffer =
-            LogBuffer(name = "test", maxSize = 1, logcatEchoTracker = tracker, systrace = false)
-
-        fun verifyDidLog(times: Int) {
-            Truth.assertThat(recentLogs).hasSize(times)
-            recentLogs.clear()
-        }
-    }
-
-    private fun verifyDidLog(times: Int) {
-        logBufferCounter.verifyDidLog(times)
-    }
-
-    companion object {
-        private val KEY = "PACKAGE_NAME"
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
index 8c3bfd5..f7632aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
@@ -30,9 +30,12 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.TestUiOffloadThread
+import com.android.systemui.UiOffloadThread
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationTemplateViewWrapper.ActionPendingIntentCancellationHandler
+import com.android.systemui.util.leak.ReferenceTestUtils.waitForCondition
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -60,6 +63,12 @@
     fun setUp() {
         looper = TestableLooper.get(this)
         allowTestableLooperAsMainThread()
+        // Use main thread instead of UI offload thread to fix flakes.
+        mDependency.injectTestDependency(
+            UiOffloadThread::class.java,
+            TestUiOffloadThread(looper.looper)
+        )
+
         helper = NotificationTestHelper(mContext, mDependency, looper)
         row = helper.createRow()
         // Some code in the view iterates through parents so we need some extra containers around
@@ -88,12 +97,11 @@
         val action2 = createActionWithPendingIntent()
         val action3 = createActionWithPendingIntent()
         wrapper.onContentUpdated(row)
-        waitForUiOffloadThread() // Wait for cancellation registration to execute.
 
         val pi3 = getPendingIntent(action3)
         pi3.cancel()
-        looper.processAllMessages() // Wait for listener callbacks to execute
 
+        waitForActionDisabled(action3)
         assertThat(action1.isEnabled).isTrue()
         assertThat(action2.isEnabled).isTrue()
         assertThat(action3.isEnabled).isFalse()
@@ -109,12 +117,12 @@
         val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
         val action = createActionWithPendingIntent()
         wrapper.onContentUpdated(row)
-        waitForUiOffloadThread() // Wait for cancellation registration to execute.
 
         // Cancel the intent and check action is now false.
         val pi = getPendingIntent(action)
         pi.cancel()
-        looper.processAllMessages() // Wait for listener callbacks to execute
+
+        waitForActionDisabled(action)
         assertThat(action.isEnabled).isFalse()
 
         // Create a NEW action and make sure that one will also be cancelled with same PI.
@@ -134,12 +142,13 @@
         val action2 = createActionWithPendingIntent()
         val action3 = createActionWithPendingIntent(getPendingIntent(action2))
         wrapper.onContentUpdated(row)
-        waitForUiOffloadThread() // Wait for cancellation registration to execute.
+        looper.processAllMessages()
 
         val pi = getPendingIntent(action2)
         pi.cancel()
-        looper.processAllMessages() // Wait for listener callbacks to execute
 
+        waitForActionDisabled(action2)
+        waitForActionDisabled(action3)
         assertThat(action1.isEnabled).isTrue()
         assertThat(action2.isEnabled).isFalse()
         assertThat(action3.isEnabled).isFalse()
@@ -152,10 +161,12 @@
         val action = createActionWithPendingIntent()
         wrapper.onContentUpdated(row)
         getPendingIntent(action).cancel()
-        ViewUtils.attachView(root)
-        waitForUiOffloadThread()
         looper.processAllMessages()
 
+        ViewUtils.attachView(root)
+        looper.processAllMessages()
+
+        waitForActionDisabled(action)
         assertThat(action.isEnabled).isFalse()
     }
 
@@ -173,7 +184,6 @@
         val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
         wrapper.onContentUpdated(row)
         ViewUtils.detachView(root)
-        waitForUiOffloadThread()
         looper.processAllMessages()
 
         val captor = ArgumentCaptor.forClass(CancelListener::class.java)
@@ -194,7 +204,6 @@
         val action = createActionWithPendingIntent(spy)
         val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
         wrapper.onContentUpdated(row)
-        waitForUiOffloadThread()
         looper.processAllMessages()
 
         // Grab set attach listener
@@ -213,7 +222,6 @@
             )
         action.setTagInternal(R.id.pending_intent_tag, newPi)
         wrapper.onContentUpdated(row)
-        waitForUiOffloadThread()
         looper.processAllMessages()
 
         // Listeners for original pending intent need to be cleaned up now.
@@ -251,4 +259,11 @@
         assertThat(pendingIntent).isNotNull()
         return pendingIntent
     }
+
+    private fun waitForActionDisabled(action: View) {
+        waitForCondition {
+            looper.processAllMessages()
+            !action.isEnabled
+        }
+    }
 }
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 236bcb4..033c96a 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;
@@ -164,6 +164,7 @@
         mFeatureFlags.setDefault(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS);
         mFeatureFlags.setDefault(Flags.NOTIFICATION_SHELF_REFACTOR);
         mFeatureFlags.setDefault(Flags.NEW_AOD_TRANSITION);
+        mFeatureFlags.setDefault(Flags.UNCLEARED_TRANSIENT_HUN_FIX);
 
         // Inject dependencies before initializing the layout
         mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags);
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 93faa77..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
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/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index f18af61..c8cbe42 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
@@ -18,6 +18,8 @@
 
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
@@ -1110,6 +1112,16 @@
         // THEN no NPE when fingerprintManager is null
     }
 
+    @Test
+    public void bubbleBarVisibility() {
+        createCentralSurfaces();
+        mCentralSurfaces.onStatusBarWindowStateChanged(WINDOW_STATE_HIDDEN);
+        verify(mBubbles).onStatusBarVisibilityChanged(false);
+
+        mCentralSurfaces.onStatusBarWindowStateChanged(WINDOW_STATE_SHOWING);
+        verify(mBubbles).onStatusBarVisibilityChanged(true);
+    }
+
     /**
      * Configures the appropriate mocks and then calls {@link CentralSurfacesImpl#updateIsKeyguard}
      * to reconfigure the keyguard to reflect the requested showing/occluded states.
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 b36d09d..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
@@ -19,8 +19,6 @@
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
 
-import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
-
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -37,6 +35,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
+
 import android.service.trust.TrustAgentService;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -175,7 +175,6 @@
         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);
 
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/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index e761635..a1da167 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -75,6 +75,8 @@
     private BluetoothAdapter mMockAdapter;
     private List<CachedBluetoothDevice> mDevices;
 
+    private FakeExecutor mBackgroundExecutor;
+
     @Before
     public void setup() throws Exception {
         mTestableLooper = TestableLooper.get(this);
@@ -91,6 +93,7 @@
         when(mMockBluetoothManager.getProfileManager())
                 .thenReturn(mock(LocalBluetoothProfileManager.class));
         mMockDumpManager = mock(DumpManager.class);
+        mBackgroundExecutor = new FakeExecutor(new FakeSystemClock());
 
         BluetoothRepository bluetoothRepository =
                 new FakeBluetoothRepository(mMockBluetoothManager);
@@ -101,6 +104,7 @@
                 mMockDumpManager,
                 mock(BluetoothLogger.class),
                 bluetoothRepository,
+                mBackgroundExecutor,
                 mTestableLooper.getLooper(),
                 mMockBluetoothManager,
                 mMockAdapter);
@@ -205,6 +209,7 @@
         mBluetoothControllerImpl.onAclConnectionStateChanged(device,
                 BluetoothProfile.STATE_CONNECTED);
         mBluetoothControllerImpl.onActiveDeviceChanged(device, BluetoothProfile.HEADSET);
+        mBackgroundExecutor.runAllReady();
 
         assertTrue(mBluetoothControllerImpl.isBluetoothAudioActive());
         assertTrue(mBluetoothControllerImpl.isBluetoothAudioProfileOnly());
@@ -290,6 +295,7 @@
                 BluetoothProfile.LE_AUDIO, /* isConnected= */ true, /* isActive= */ false);
 
         mBluetoothControllerImpl.onDeviceAdded(device);
+        mBackgroundExecutor.runAllReady();
 
         assertThat(mBluetoothControllerImpl.isBluetoothAudioProfileOnly()).isTrue();
     }
@@ -300,6 +306,7 @@
                 BluetoothProfile.HEADSET, /* isConnected= */ true, /* isActive= */ false);
 
         mBluetoothControllerImpl.onDeviceAdded(device);
+        mBackgroundExecutor.runAllReady();
 
         assertThat(mBluetoothControllerImpl.isBluetoothAudioProfileOnly()).isTrue();
     }
@@ -310,6 +317,7 @@
                 BluetoothProfile.A2DP, /* isConnected= */ true, /* isActive= */ false);
 
         mBluetoothControllerImpl.onDeviceAdded(device);
+        mBackgroundExecutor.runAllReady();
 
         assertThat(mBluetoothControllerImpl.isBluetoothAudioProfileOnly()).isTrue();
     }
@@ -320,6 +328,7 @@
                 BluetoothProfile.HEARING_AID, /* isConnected= */ true, /* isActive= */ false);
 
         mBluetoothControllerImpl.onDeviceAdded(device);
+        mBackgroundExecutor.runAllReady();
 
         assertThat(mBluetoothControllerImpl.isBluetoothAudioProfileOnly()).isTrue();
     }
@@ -337,6 +346,8 @@
         mBluetoothControllerImpl.onDeviceAdded(device2);
         mBluetoothControllerImpl.onDeviceAdded(device3);
 
+        mBackgroundExecutor.runAllReady();
+
         assertThat(mBluetoothControllerImpl.isBluetoothAudioProfileOnly()).isTrue();
     }
 
@@ -349,6 +360,7 @@
 
         mBluetoothControllerImpl.onDeviceAdded(device1);
         mBluetoothControllerImpl.onDeviceAdded(device2);
+        mBackgroundExecutor.runAllReady();
 
         assertThat(mBluetoothControllerImpl.isBluetoothAudioProfileOnly()).isFalse();
     }
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/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/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/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/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 813197b1..dc5fd95 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
@@ -24,6 +24,7 @@
 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(
@@ -36,6 +37,7 @@
             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 d6632a3..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,19 +35,15 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.uiautomator.UiDevice;
 
-import com.android.keyguard.KeyguardUpdateMonitor;
-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.dump.DumpManager;
 import com.android.systemui.settings.UserTracker;
-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;
 
@@ -69,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
@@ -94,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(),
@@ -124,13 +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);
-        mDependency.injectMockDependency(KeyguardUpdateMonitor.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/TestUiOffloadThread.java b/packages/SystemUI/tests/utils/src/com/android/systemui/TestUiOffloadThread.java
new file mode 100644
index 0000000..fdd26eb
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestUiOffloadThread.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+
+/**
+ * UiOffloadThread that can be used for testing as part of {@link TestableDependency}.
+ */
+public class TestUiOffloadThread extends UiOffloadThread {
+    private final Handler mTestHandler;
+
+    public TestUiOffloadThread(Looper looper) {
+        mTestHandler = new Handler(looper);
+    }
+
+    @Override
+    public Future<?> execute(Runnable runnable) {
+        Looper myLooper = Looper.myLooper();
+        if (myLooper != null && myLooper.isCurrentThread()) {
+            try {
+                runnable.run();
+                return CompletableFuture.completedFuture(null);
+            } catch (Exception e) {
+                return CompletableFuture.failedFuture(e);
+            }
+        }
+
+        final CompletableFuture<?> future = new CompletableFuture<>();
+        mTestHandler.post(() -> {
+            try {
+                runnable.run();
+                future.complete(null);
+            } catch (Exception e) {
+                future.completeExceptionally(e);
+            }
+        });
+
+        return future;
+    }
+}
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/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 29fb52a..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,6 +15,7 @@
  */
 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
@@ -29,6 +30,7 @@
 @Module(
     includes =
         [
+            FakeAuthenticationDataLayerModule::class,
             FakeBouncerDataLayerModule::class,
             FakeCommonDataLayerModule::class,
             FakeDeviceEntryDataLayerModule::class,
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 26d95c0..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,3 +1,18 @@
+/*
+ * 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
@@ -13,15 +28,13 @@
 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
     }
@@ -35,7 +48,7 @@
     }
 
     fun setBypassEnabled(isBypassEnabled: Boolean) {
-        this.isBypassEnabled = isBypassEnabled
+        _isBypassEnabled.value = isBypassEnabled
     }
 }
 
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 bf77b1a..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
@@ -53,7 +53,7 @@
 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/statusbar/data/FakeStatusBarDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
index 822edfc7..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,6 +16,7 @@
 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
@@ -24,6 +25,7 @@
     includes =
         [
             FakeStatusBarDisableFlagsDataLayerModule::class,
+            FakeStatusBarNotificationsDataLayerModule::class,
             FakeStatusBarPipelineDataLayerModule::class,
             FakeStatusBarPolicyDataLayerModule::class,
         ]
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/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/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/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodNativeSubstitutionClass.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodNativeSubstitutionClass.java
new file mode 100644
index 0000000..eb883e2
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodNativeSubstitutionClass.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * TODO: Javadoc
+ */
+@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/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodThrow.java b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodThrow.java
new file mode 100644
index 0000000..a329d84
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotations/RavenwoodThrow.java
@@ -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 android.ravenwood.annotations;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+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
+ * TODO: Create "whole-class-throw"?
+ */
+@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 6fa9c08..10ac2eb 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -40,4 +40,11 @@
     namespace: "accessibility"
     description: "Whether to set min span of ScaleGestureDetector to zero."
     bug: "295327792"
-}
\ No newline at end of file
+}
+
+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/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/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index 123b65c..b37bbd6 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -8,6 +8,13 @@
 }
 
 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"
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/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 8a2aa61..f5562d2 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -122,9 +122,9 @@
     private static final String TAG = "VirtualDeviceImpl";
 
     /**
-     * Virtual displays created by a {@link VirtualDeviceManager.VirtualDevice} are more consistent
-     * with virtual displays created via {@link DisplayManager} and allow for the creation of
-     * private, auto-mirror, and fixed orientation displays since
+     * Virtual displays created by a {@code VirtualDeviceManager.VirtualDevice} are more consistent
+     * with virtual displays created via {@link android.hardware.display.DisplayManager} and allow
+     * for the creation of private, auto-mirror, and fixed orientation displays since
      * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}.
      *
      * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC
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/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index f594170..1a8dd3a 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -20,6 +20,9 @@
 import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
 import static android.service.contentcapture.ContentCaptureService.setClientState;
 import static android.view.contentcapture.ContentCaptureHelper.toList;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
@@ -112,6 +115,7 @@
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -203,6 +207,17 @@
     @GuardedBy("mLock")
     int mDevCfgContentProtectionBufferSize;
 
+    @GuardedBy("mLock")
+    @NonNull
+    List<List<String>> mDevCfgContentProtectionRequiredGroups;
+
+    @GuardedBy("mLock")
+    @NonNull
+    List<List<String>> mDevCfgContentProtectionOptionalGroups;
+
+    @GuardedBy("mLock")
+    int mDevCfgContentProtectionOptionalGroupsThreshold;
+
     private final Executor mDataShareExecutor = Executors.newCachedThreadPool();
     private final Handler mHandler = new Handler(Looper.getMainLooper());
 
@@ -226,6 +241,11 @@
                 com.android.internal.R.string.config_defaultContentCaptureService),
                 UserManager.DISALLOW_CONTENT_CAPTURE,
                 /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_NO_REFRESH);
+
+        mDevCfgContentProtectionRequiredGroups =
+                ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_REQUIRED_GROUPS;
+        mDevCfgContentProtectionOptionalGroups =
+                ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS;
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ActivityThread.currentApplication().getMainExecutor(),
                 (properties) -> onDeviceConfigChange(properties));
@@ -422,6 +442,9 @@
                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE:
                 case ContentCaptureManager
                         .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE:
+                case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG:
+                case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG:
+                case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD:
                     setFineTuneParamsFromDeviceConfig();
                     return;
                 default:
@@ -433,6 +456,8 @@
     /** @hide */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected void setFineTuneParamsFromDeviceConfig() {
+        String contentProtectionRequiredGroupsConfig;
+        String contentProtectionOptionalGroupsConfig;
         synchronized (mLock) {
             mDevCfgMaxBufferSize =
                     DeviceConfig.getInt(
@@ -486,6 +511,24 @@
                             ContentCaptureManager
                                     .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE,
                             ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE);
+            contentProtectionRequiredGroupsConfig =
+                    DeviceConfig.getString(
+                            DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                            DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG,
+                            ContentCaptureManager
+                                    .DEFAULT_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG);
+            contentProtectionOptionalGroupsConfig =
+                    DeviceConfig.getString(
+                            DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                            DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG,
+                            ContentCaptureManager
+                                    .DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG);
+            mDevCfgContentProtectionOptionalGroupsThreshold =
+                    DeviceConfig.getInt(
+                            DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                            DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD,
+                            ContentCaptureManager
+                                    .DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD);
             if (verbose) {
                 Slog.v(
                         TAG,
@@ -507,9 +550,24 @@
                                 + ", contentProtectionAppsBlocklistSize="
                                 + mDevCfgContentProtectionAppsBlocklistSize
                                 + ", contentProtectionBufferSize="
-                                + mDevCfgContentProtectionBufferSize);
+                                + mDevCfgContentProtectionBufferSize
+                                + ", contentProtectionRequiredGroupsConfig="
+                                + contentProtectionRequiredGroupsConfig
+                                + ", contentProtectionOptionalGroupsConfig="
+                                + contentProtectionOptionalGroupsConfig
+                                + ", contentProtectionOptionalGroupsThreshold="
+                                + mDevCfgContentProtectionOptionalGroupsThreshold);
             }
         }
+
+        List<List<String>> contentProtectionRequiredGroups =
+                parseContentProtectionGroupsConfig(contentProtectionRequiredGroupsConfig);
+        List<List<String>> contentProtectionOptionalGroups =
+                parseContentProtectionGroupsConfig(contentProtectionOptionalGroupsConfig);
+        synchronized (mLock) {
+            mDevCfgContentProtectionRequiredGroups = contentProtectionRequiredGroups;
+            mDevCfgContentProtectionOptionalGroups = contentProtectionOptionalGroups;
+        }
     }
 
     private void setLoggingLevelFromDeviceConfig() {
@@ -786,6 +844,15 @@
         pw.print(prefix2);
         pw.print("contentProtectionBufferSize: ");
         pw.println(mDevCfgContentProtectionBufferSize);
+        pw.print(prefix2);
+        pw.print("contentProtectionRequiredGroupsSize: ");
+        pw.println(mDevCfgContentProtectionRequiredGroups.size());
+        pw.print(prefix2);
+        pw.print("contentProtectionOptionalGroupsSize: ");
+        pw.println(mDevCfgContentProtectionOptionalGroups.size());
+        pw.print(prefix2);
+        pw.print("contentProtectionOptionalGroupsThreshold: ");
+        pw.println(mDevCfgContentProtectionOptionalGroupsThreshold);
         pw.print(prefix);
         pw.println("Global Options:");
         mGlobalContentCaptureOptions.dump(prefix2, pw);
@@ -890,6 +957,16 @@
         return mContentCaptureManagerServiceStub;
     }
 
+    /** @hide */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    @NonNull
+    protected List<List<String>> parseContentProtectionGroupsConfig(@Nullable String config) {
+        if (verbose) {
+            Slog.v(TAG, "parseContentProtectionGroupsConfig: " + config);
+        }
+        return Collections.emptyList();
+    }
+
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
 
         @Override
@@ -1277,7 +1354,10 @@
                                 isContentCaptureReceiverEnabled || whitelistedComponents != null,
                                 new ContentCaptureOptions.ContentProtectionOptions(
                                         isContentProtectionReceiverEnabled,
-                                        mDevCfgContentProtectionBufferSize),
+                                        mDevCfgContentProtectionBufferSize,
+                                        mDevCfgContentProtectionRequiredGroups,
+                                        mDevCfgContentProtectionOptionalGroups,
+                                        mDevCfgContentProtectionOptionalGroupsThreshold),
                                 whitelistedComponents);
                 if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options);
                 return options;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 6521fab..6dd32bc 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -182,7 +182,9 @@
         "android.hidl.manager-V1.2-java",
         "cbor-java",
         "display_flags_lib",
+        "dropbox_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/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 55069b7..f82a6aa 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -16,10 +16,14 @@
 
 package com.android.server;
 
+import android.Manifest;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -30,6 +34,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.BundleMerger;
 import android.os.Debug;
@@ -66,6 +71,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ObjectUtils;
 import com.android.server.DropBoxManagerInternal.EntrySource;
+import com.android.server.feature.flags.Flags;
 
 import libcore.io.IoUtils;
 
@@ -89,6 +95,13 @@
  * Clients use {@link DropBoxManager} to access this service.
  */
 public final class DropBoxManagerService extends SystemService {
+    /**
+     * For Android U and earlier versions, apps can continue to use the READ_LOGS permission,
+     * but for all subsequent versions, the READ_DROPBOX_DATA permission must be used.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    private static final long ENFORCE_READ_DROPBOX_DATA = 296060945L;
     private static final String TAG = "DropBoxManagerService";
     private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
     private static final int DEFAULT_MAX_FILES = 1000;
@@ -109,7 +122,6 @@
     // Tags that we should drop by default.
     private static final List<String> DISABLED_BY_DEFAULT_TAGS =
             List.of("data_app_wtf", "system_app_wtf", "system_server_wtf");
-
     // TODO: This implementation currently uses one file per entry, which is
     // inefficient for smallish entries -- consider using a single queue file
     // per tag (or even globally) instead.
@@ -291,8 +303,21 @@
             if (!DropBoxManagerService.this.mBooted) {
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             }
-            getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
-                    android.Manifest.permission.READ_LOGS, options);
+            if (Flags.enableReadDropboxPermission()) {
+                BroadcastOptions unbundledOptions = (options == null)
+                        ? BroadcastOptions.makeBasic() : BroadcastOptions.fromBundle(options);
+
+                unbundledOptions.setRequireCompatChange(ENFORCE_READ_DROPBOX_DATA, true);
+                getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+                        Manifest.permission.READ_DROPBOX_DATA, unbundledOptions.toBundle());
+
+                unbundledOptions.setRequireCompatChange(ENFORCE_READ_DROPBOX_DATA, false);
+                getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+                        Manifest.permission.READ_LOGS, unbundledOptions.toBundle());
+            } else {
+                getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+                        android.Manifest.permission.READ_LOGS, options);
+            }
         }
 
         private Intent createIntent(String tag, long time) {
@@ -572,9 +597,16 @@
             return true;
         }
 
+
+        String permission = Manifest.permission.READ_LOGS;
+        if (Flags.enableReadDropboxPermission()
+                && CompatChanges.isChangeEnabled(ENFORCE_READ_DROPBOX_DATA, callingUid)) {
+            permission = Manifest.permission.READ_DROPBOX_DATA;
+        }
+
         // Callers always need this permission
-        getContext().enforceCallingOrSelfPermission(
-                android.Manifest.permission.READ_LOGS, TAG);
+        getContext().enforceCallingOrSelfPermission(permission, TAG);
+
 
         // Callers also need the ability to read usage statistics
         switch (getContext().getSystemService(AppOpsManager.class).noteOp(
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/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 93dca2f..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();
     }
 
     /**
@@ -560,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;
     }
 
@@ -604,7 +621,6 @@
             int key = currentPinKeys.valueAt(i);
             pinApp(key, userHandle, true /* force */);
         }
-        pinAnonRegion();
     }
 
     /**
@@ -689,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;
@@ -700,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;
@@ -729,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;
@@ -744,6 +784,8 @@
         if (mPinAnonAddress != 0) {
             safeMunmap(mPinAnonAddress, mCurrentlyPinnedAnonSize);
         }
+        mPinAnonAddress = 0;
+        mCurrentlyPinnedAnonSize = 0;
     }
 
     /**
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/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 553b085..0956c6d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -409,6 +409,13 @@
 
     AppWidgetManagerInternal mAppWidgetManagerInternal;
 
+    /**
+     * The available ANR timers.
+     */
+    private final ProcessAnrTimer mActiveServiceAnrTimer;
+    private final ServiceAnrTimer mShortFGSAnrTimer;
+    private final ServiceAnrTimer mServiceFGAnrTimer;
+
     // allowlisted packageName.
     ArraySet<String> mAllowListWhileInUsePermissionInFgs = new ArraySet<>();
 
@@ -663,6 +670,15 @@
 
         final IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
         this.mFGSLogger = new ForegroundServiceTypeLoggerModule();
+        this.mActiveServiceAnrTimer = new ProcessAnrTimer(service,
+                ActivityManagerService.SERVICE_TIMEOUT_MSG,
+                "SERVICE_TIMEOUT");
+        this.mShortFGSAnrTimer = new ServiceAnrTimer(service,
+                ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG,
+                "FGS_TIMEOUT");
+        this.mServiceFGAnrTimer = new ServiceAnrTimer(service,
+                ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG,
+                "SERVICE_FOREGROUND_TIMEOUT");
     }
 
     void systemServicesReady() {
@@ -2083,8 +2099,7 @@
                 r.fgRequired = false;
                 r.fgWaiting = false;
                 alreadyStartedOp = stopProcStatsOp = true;
-                mAm.mHandler.removeMessages(
-                        ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
+                mServiceFGAnrTimer.cancel(r);
             }
 
             final ProcessServiceRecord psr = r.app.mServices;
@@ -3313,7 +3328,7 @@
     }
 
     void unscheduleShortFgsTimeoutLocked(ServiceRecord sr) {
-        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
+        mShortFGSAnrTimer.cancel(sr);
         mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG,
                 sr);
         mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_TIMEOUT_MSG, sr);
@@ -3387,9 +3402,11 @@
                     Slog.d(TAG_SERVICE, "[STALE] Short FGS timed out: " + sr
                             + " " + sr.getShortFgsTimedEventDescription(nowUptime));
                 }
+                mShortFGSAnrTimer.discard(sr);
                 return;
             }
             Slog.e(TAG_SERVICE, "Short FGS timed out: " + sr);
+            mShortFGSAnrTimer.accept(sr);
             traceInstant("short FGS timeout: ", sr);
 
             logFGSStateChangeLocked(sr,
@@ -3413,11 +3430,10 @@
                         msg, sr.getShortFgsInfo().getProcStateDemoteTime());
             }
 
-            {
-                final Message msg = mAm.mHandler.obtainMessage(
-                        ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
-                mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getAnrTime());
-            }
+            // ServiceRecord.getAnrTime() is an absolute time with a reference that is not "now".
+            // Compute the time from "now" when starting the anr timer.
+            mShortFGSAnrTimer.start(sr,
+                    sr.getShortFgsInfo().getAnrTime() - SystemClock.uptimeMillis());
         }
     }
 
@@ -4847,8 +4863,7 @@
         // a new SERVICE_FOREGROUND_TIMEOUT_MSG is scheduled in SERVICE_START_FOREGROUND_TIMEOUT
         // again.
         if (r.fgRequired && r.fgWaiting) {
-            mAm.mHandler.removeMessages(
-                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
+            mServiceFGAnrTimer.cancel(r);
             r.fgWaiting = false;
         }
 
@@ -5691,8 +5706,7 @@
             }
             mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                     AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
-            mAm.mHandler.removeMessages(
-                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
+            mServiceFGAnrTimer.cancel(r);
             if (r.app != null) {
                 Message msg = mAm.mHandler.obtainMessage(
                         ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
@@ -6128,7 +6142,7 @@
                 if (psr.numberOfExecutingServices() == 0) {
                     if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                             "No more executingServices of " + r.shortInstanceName);
-                    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
+                    if (r.app.mPid != 0) mActiveServiceAnrTimer.cancel(r.app);
                 } else if (r.executeFg) {
                     // Need to re-evaluate whether the app still needs to be in the foreground.
                     for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
@@ -6816,13 +6830,16 @@
             synchronized (mAm) {
                 if (proc.isDebugging()) {
                     // The app's being debugged, ignore timeout.
+                    mActiveServiceAnrTimer.discard(proc);
                     return;
                 }
                 final ProcessServiceRecord psr = proc.mServices;
                 if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null
                         || proc.isKilled()) {
+                    mActiveServiceAnrTimer.discard(proc);
                     return;
                 }
+                mActiveServiceAnrTimer.accept(proc);
                 final long now = SystemClock.uptimeMillis();
                 final long maxTime =  now
                         - (psr.shouldExecServicesFg()
@@ -6855,12 +6872,11 @@
                     timeoutRecord = TimeoutRecord.forServiceExec(timeout.shortInstanceName,
                             waitedMillis);
                 } else {
-                    Message msg = mAm.mHandler.obtainMessage(
-                            ActivityManagerService.SERVICE_TIMEOUT_MSG);
-                    msg.obj = proc;
-                    mAm.mHandler.sendMessageAtTime(msg, psr.shouldExecServicesFg()
-                            ? (nextTime + mAm.mConstants.SERVICE_TIMEOUT) :
-                            (nextTime + mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT));
+                    final long delay = psr.shouldExecServicesFg()
+                                       ? (nextTime + mAm.mConstants.SERVICE_TIMEOUT) :
+                                       (nextTime + mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT)
+                                       - SystemClock.uptimeMillis();
+                    mActiveServiceAnrTimer.start(proc, delay);
                 }
             }
 
@@ -6886,12 +6902,15 @@
             synchronized (mAm) {
                 timeoutRecord.mLatencyTracker.waitingOnAMSLockEnded();
                 if (!r.fgRequired || !r.fgWaiting || r.destroying) {
+                    mServiceFGAnrTimer.discard(r);
                     return;
                 }
 
+                mServiceFGAnrTimer.accept(r);
                 app = r.app;
                 if (app != null && app.isDebugging()) {
                     // The app's being debugged; let it ride
+                    mServiceFGAnrTimer.discard(r);
                     return;
                 }
 
@@ -6948,26 +6967,46 @@
                 ForegroundServiceDidNotStartInTimeException.createExtrasForService(service));
     }
 
+    private static class ProcessAnrTimer extends AnrTimer<ProcessRecord> {
+
+        ProcessAnrTimer(ActivityManagerService am, int msg, String label) {
+            super(Objects.requireNonNull(am).mHandler, msg, label);
+        }
+
+        void start(@NonNull ProcessRecord proc, long millis) {
+            start(proc, proc.getPid(), proc.uid, millis);
+        }
+    }
+
+    private static class ServiceAnrTimer extends AnrTimer<ServiceRecord> {
+
+        ServiceAnrTimer(ActivityManagerService am, int msg, String label) {
+            super(Objects.requireNonNull(am).mHandler, msg, label);
+        }
+
+        void start(@NonNull ServiceRecord service, long millis) {
+            start(service,
+                    (service.app != null) ? service.app.getPid() : 0,
+                    service.appInfo.uid,
+                    millis);
+        }
+    }
+
     void scheduleServiceTimeoutLocked(ProcessRecord proc) {
         if (proc.mServices.numberOfExecutingServices() == 0 || proc.getThread() == null) {
             return;
         }
-        Message msg = mAm.mHandler.obtainMessage(
-                ActivityManagerService.SERVICE_TIMEOUT_MSG);
-        msg.obj = proc;
-        mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
-                ? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT);
+        final long delay = proc.mServices.shouldExecServicesFg()
+                ? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT;
+        mActiveServiceAnrTimer.start(proc, delay);
     }
 
     void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
         if (r.app.mServices.numberOfExecutingServices() == 0 || r.app.getThread() == null) {
             return;
         }
-        Message msg = mAm.mHandler.obtainMessage(
-                ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
-        msg.obj = r;
         r.fgWaiting = true;
-        mAm.mHandler.sendMessageDelayed(msg, mAm.mConstants.mServiceStartForegroundTimeoutMs);
+        mServiceFGAnrTimer.start(r, mAm.mConstants.mServiceStartForegroundTimeoutMs);
     }
 
     final class ServiceDumper {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d3ce47c..b43b986 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.
@@ -1531,6 +1532,11 @@
      */
     int mBootPhase;
 
+    /**
+     * The time stamp that all apps have received BOOT_COMPLETED.
+     */
+    volatile long mBootCompletedTimestamp;
+
     @GuardedBy("this")
     boolean mDeterministicUidIdle = false;
 
@@ -1630,7 +1636,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 +1990,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 +4163,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 +4760,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 +4798,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 +4878,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 +5016,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.
      */
@@ -5126,10 +5169,14 @@
                         public void performReceive(Intent intent, int resultCode,
                                 String data, Bundle extras, boolean ordered,
                                 boolean sticky, int sendingUser) {
-                            synchronized (mProcLock) {
-                                mAppProfiler.requestPssAllProcsLPr(
-                                        SystemClock.uptimeMillis(), true, false);
-                            }
+                            mBootCompletedTimestamp = SystemClock.uptimeMillis();
+                            // Defer the full Pss collection as the system is really busy now.
+                            mHandler.postDelayed(() -> {
+                                synchronized (mProcLock) {
+                                    mAppProfiler.requestPssAllProcsLPr(
+                                            SystemClock.uptimeMillis(), true, false);
+                                }
+                            }, mConstants.FULL_PSS_MIN_INTERVAL);
                         }
                     });
             maybeLogUserspaceRebootEvent();
diff --git a/services/core/java/com/android/server/am/AnrTimer.java b/services/core/java/com/android/server/am/AnrTimer.java
index 9ba49ce..3e17930 100644
--- a/services/core/java/com/android/server/am/AnrTimer.java
+++ b/services/core/java/com/android/server/am/AnrTimer.java
@@ -28,6 +28,7 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.text.TextUtils;
+import android.text.format.TimeMigrationUtils;
 import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
@@ -44,7 +45,6 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Date;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -150,7 +150,7 @@
         /** A partial stack that localizes the caller of the operation. */
         final StackTraceElement[] stack;
         /** The date, in local time, the error was created. */
-        final String date;
+        final long timestamp;
 
         Error(@NonNull String issue, @NonNull String operation, @NonNull String tag,
                 @NonNull StackTraceElement[] stack, @NonNull String arg) {
@@ -159,7 +159,7 @@
             this.tag = tag;
             this.stack = stack;
             this.arg = arg;
-            this.date = new Date().toString();
+            this.timestamp = SystemClock.elapsedRealtime();
         }
     }
 
@@ -347,20 +347,23 @@
          * main Looper.
          */
         @NonNull
-        Handler getHandler(@NonNull Handler.Callback callback) {
+        Handler newHandler(@NonNull Handler.Callback callback) {
             Looper looper = mReferenceHandler.getLooper();
             if (looper == null) looper = Looper.getMainLooper();
             return new Handler(looper, callback);
-        };
+        }
 
-        /** Return a CpuTracker. */
+        /**
+         * Return a CpuTracker. The default behavior is to create a new CpuTracker but this changes
+         * for unit tests.
+         **/
         @NonNull
-        CpuTracker getTracker() {
+        CpuTracker newTracker() {
             return new CpuTracker();
         }
 
         /** Return true if the feature is enabled. */
-        boolean getFeatureEnabled() {
+        boolean isFeatureEnabled() {
             return anrTimerServiceEnabled();
         }
     }
@@ -401,8 +404,8 @@
         /** Create a HandlerTimerService that directly uses the supplied handler and tracker. */
         @VisibleForTesting
         HandlerTimerService(@NonNull Injector injector) {
-            mHandler = injector.getHandler(this::expires);
-            mCpu = injector.getTracker();
+            mHandler = injector.newHandler(this::expires);
+            mCpu = injector.newTracker();
         }
 
         /** Post a message with the specified timeout.  The timer is not modified. */
@@ -513,7 +516,26 @@
     private final FeatureSwitch mFeature;
 
     /**
-     * The common constructor.  A null injector results in a normal, production timer.
+     * Create one AnrTimer instance.  The instance is given a handler and a "what".  Individual
+     * timers are started with {@link #start}.  If a timer expires, then a {@link Message} is sent
+     * immediately to the handler with {@link Message.what} set to what and {@link Message.obj} set
+     * to the timer key.
+     *
+     * AnrTimer instances have a label, which must be unique.  The label is used for reporting and
+     * debug.
+     *
+     * If an individual timer expires internally, and the "extend" parameter is true, then the
+     * AnrTimer may extend the individual timer rather than immediately delivering the timeout to
+     * the client.  The extension policy is not part of the instance.
+     *
+     * This method accepts an {@link #Injector} to tune behavior for testing.  This method should
+     * not be called directly by regular clients.
+     *
+     * @param handler The handler to which the expiration message will be delivered.
+     * @param what The "what" parameter for the expiration message.
+     * @param label A name for this instance.
+     * @param extend A flag to indicate if expired timers can be granted extensions.
+     * @param injector An {@link #Injector} to tune behavior for testing.
      */
     @VisibleForTesting
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend,
@@ -522,7 +544,7 @@
         mWhat = what;
         mLabel = label;
         mExtend = extend;
-        boolean enabled = injector.getFeatureEnabled();
+        boolean enabled = injector.isFeatureEnabled();
         if (!enabled) {
             mFeature = new FeatureDisabled();
             mTimerService = null;
@@ -538,14 +560,25 @@
     }
 
     /**
-     * Create one timer instance for production.  The client can ask for extensible timeouts.
+     * Create an AnrTimer instance with the default {@link #Injector}.  See {@link AnrTimer(Handler,
+     * int, String, boolean, Injector} for a functional description.
+     *
+     * @param handler The handler to which the expiration message will be delivered.
+     * @param what The "what" parameter for the expiration message.
+     * @param label A name for this instance.
+     * @param extend A flag to indicate if expired timers can be granted extensions.
      */
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) {
         this(handler, what, label, extend, new Injector(handler));
     }
 
     /**
-     * Create one timer instance for production.  There are no extensible timeouts.
+     * Create an AnrTimer instance with the default {@link #Injector} and with extensions disabled.
+     * See {@link AnrTimer(Handler, int, String, boolean, Injector} for a functional description.
+     *
+     * @param handler The handler to which the expiration message will be delivered.
+     * @param what The "what" parameter for the expiration message.
+     * @param label A name for this instance.
      */
     AnrTimer(@NonNull Handler handler, int what, @NonNull String label) {
         this(handler, what, label, false);
@@ -555,6 +588,8 @@
      * 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.
+     *
+     * @return true if the service is flag-enabled.
      */
     boolean serviceEnabled() {
         return mFeature.enabled();
@@ -642,7 +677,7 @@
     }
 
     /**
-     * Report something about a timer.
+     * Generate a log message for a timer.
      */
     private void report(@NonNull Timer timer, @NonNull String msg) {
         Log.i(TAG, msg + " " + timer + " " + Objects.toString(timer.arg));
@@ -654,9 +689,13 @@
      */
     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();
     }
 
@@ -666,6 +705,7 @@
      */
     private class FeatureDisabled extends FeatureSwitch {
         /** Start a timer by sending a message to the client's handler. */
+        @Override
         boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
             final Message msg = mHandler.obtainMessage(mWhat, arg);
             mHandler.sendMessageDelayed(msg, timeoutMs);
@@ -673,22 +713,26 @@
         }
 
         /** Cancel a timer by removing the message from the client's handler. */
+        @Override
         boolean cancel(@NonNull V arg) {
             mHandler.removeMessages(mWhat, arg);
             return true;
         }
 
         /** accept() is a no-op when the feature is disabled. */
+        @Override
         boolean accept(@NonNull V arg) {
             return true;
         }
 
         /** discard() is a no-op when the feature is disabled. */
+        @Override
         boolean discard(@NonNull V arg) {
             return true;
         }
 
         /** The feature is not enabled. */
+        @Override
         boolean enabled() {
             return false;
         }
@@ -703,16 +747,17 @@
         /**
          * Start a timer.
          */
+        @Override
         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);
+                // There is an existing timer.  If the timer was running, then cancel the running
+                // timer and restart it.  If the timer was expired record a protocol error and
+                // discard the expired timer.
                 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) {
+                      restartedLocked(old.status, arg);
                         discard(arg);
                     } else {
                         cancel(arg);
@@ -735,6 +780,7 @@
         /**
          * Cancel a timer.  Return false if the timer was not found.
          */
+        @Override
         boolean cancel(@NonNull V arg) {
             synchronized (mLock) {
                 Timer timer = removeLocked(arg);
@@ -755,6 +801,7 @@
          * 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.
          */
+        @Override
         boolean accept(@NonNull V arg) {
             synchronized (mLock) {
                 Timer timer = removeLocked(arg);
@@ -775,6 +822,7 @@
          * longer interesting.  No statistics are collected.  Return false if the time was not
          * found.
          */
+        @Override
         boolean discard(@NonNull V arg) {
             synchronized (mLock) {
                 Timer timer = removeLocked(arg);
@@ -791,40 +839,58 @@
         }
 
         /** The feature is enabled. */
+        @Override
         boolean enabled() {
             return true;
         }
     }
 
     /**
-     * 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.
+     * Start a timer associated with arg.  The same object must be used to cancel, accept, or
+     * discard a timer later.  If a timer already exists with the same arg, then the existing timer
+     * is canceled and a new timer is created.
+     *
+     * @param arg The key by which the timer is known.  This is never examined or modified.
+     * @param pid The Linux process ID of the target being timed.
+     * @param uid The Linux user ID of the target being timed.
+     * @param timeoutMs The timer timeout, in milliseconds.
+     * @return true if the timer was successfully 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.
+     * Cancel the running timer associated with arg.  The timer is forgotten.  If the timer has
+     * expired, the call is treated as a discard.  No errors are reported if the timer does not
+     * exist or if the timer has expired.
+     *
+     * @return true if the timer was found and was running.
      */
     boolean cancel(@NonNull V arg) {
         return mFeature.cancel(arg);
     }
 
     /**
-     * Accept an expired timer.  This returns false if the timer was not found or if the timer was
-     * not expired.
+     * Accept the expired timer associated with arg.  This indicates that the caller considers the
+     * timer expiration to be a true ANR.  (See {@link #discard} for an alternate response.)  It is
+     * an error to accept a running timer, however the running timer will be canceled.
+     *
+     * @return true if the timer was found and was expired.
      */
     boolean accept(@NonNull V arg) {
         return mFeature.accept(arg);
     }
 
     /**
-     * Discard an expired timer.  This returns false if the timer was not found or if the timer was
-     * not expired.
+     * Discard the expired timer associated with arg.  This indicates that the caller considers the
+     * timer expiration to be a false ANR.  ((See {@link #accept} for an alternate response.)  One
+     * reason to discard an expired timer is if the process being timed was also being debugged:
+     * such a process could be stopped at a breakpoint and its failure to respond would not be an
+     * error.  It is an error to discard a running timer, however the running timer will be
+     * canceled.
+     *
+     * @return true if the timer was found and was expired.
      */
     boolean discard(@NonNull V arg) {
         return mFeature.discard(arg);
@@ -913,7 +979,10 @@
     private static void dump(IndentingPrintWriter ipw, int seq, Error err) {
         ipw.format("%2d: op:%s tag:%s issue:%s arg:%s\n", seq, err.operation, err.tag,
                 err.issue, err.arg);
-        ipw.format("    date:%s\n", err.date);
+
+        final long offset = System.currentTimeMillis() - SystemClock.elapsedRealtime();
+        final long etime = offset + err.timestamp;
+        ipw.println("    date:" + TimeMigrationUtils.formatMillisWithFixedFormat(etime));
         ipw.increaseIndent();
         for (int i = 0; i < err.stack.length; i++) {
             ipw.println("    " + err.stack[i].toString());
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/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index a428907..d19eae5 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -258,7 +258,8 @@
     private static final int MSG_PROCESS_FREEZABLE_CHANGED = 6;
     private static final int MSG_UID_STATE_CHANGED = 7;
 
-    // Required when Flags.anrTimerServiceEnabled is false.
+    // Required when Flags.anrTimerServiceEnabled is false.  This constant should be deleted if and
+    // when the flag is fused on.
     private static final int MSG_DELIVERY_TIMEOUT_SOFT = 8;
 
     private void enqueueUpdateRunningList() {
@@ -274,7 +275,8 @@
                 updateRunningList();
                 return true;
             }
-            // Required when Flags.anrTimerServiceEnabled is false.
+            // Required when Flags.anrTimerServiceEnabled is false.  This case should be deleted if
+            // and when the flag is fused on.
             case MSG_DELIVERY_TIMEOUT_SOFT: {
                 synchronized (mService) {
                     deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1);
@@ -1169,7 +1171,8 @@
         r.resultTo = null;
     }
 
-    // Required when Flags.anrTimerServiceEnabled is false.
+    // Required when Flags.anrTimerServiceEnabled is false.  This function can be replaced with a
+    // single call to {@code mAnrTimer.start()} if and when the flag is fused on.
     private void startDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue,
             int softTimeoutMillis) {
         if (mAnrTimer.serviceEnabled()) {
@@ -1181,7 +1184,8 @@
         }
     }
 
-    // Required when Flags.anrTimerServiceEnabled is false.
+    // Required when Flags.anrTimerServiceEnabled is false. This function can be replaced with a
+    // single call to {@code mAnrTimer.cancel()} if and when the flag is fused on.
     private void cancelDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue) {
         mAnrTimer.cancel(queue);
         if (!mAnrTimer.serviceEnabled()) {
@@ -1189,7 +1193,8 @@
         }
     }
 
-    // Required when Flags.anrTimerServiceEnabled is false.
+    // Required when Flags.anrTimerServiceEnabled is false.  This function can be deleted entirely
+    // if and when the flag is fused on.
     private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue,
             int softTimeoutMillis) {
         if (queue.app != null) {
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/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4572766..e0e6cad 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1439,7 +1439,7 @@
     }
 
     public static long computeNextPssTime(int procState, ProcStateMemTracker tracker, boolean test,
-            boolean sleeping, long now) {
+            boolean sleeping, long now, long earliest) {
         boolean first;
         float scalingFactor;
         final int memState = sProcStateToProcMem[procState];
@@ -1470,7 +1470,7 @@
         if (delay > PSS_MAX_INTERVAL) {
             delay = PSS_MAX_INTERVAL;
         }
-        return now + delay;
+        return Math.max(now + delay, earliest);
     }
 
     long getMemLevel(int adjustment) {
diff --git a/services/core/java/com/android/server/am/ProcessProfileRecord.java b/services/core/java/com/android/server/am/ProcessProfileRecord.java
index db74f1a..940c58b 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"})
@@ -570,7 +575,11 @@
 
     @GuardedBy("mProfilerLock")
     long computeNextPssTime(int procState, boolean test, boolean sleeping, long now) {
-        return ProcessList.computeNextPssTime(procState, mProcStateMemTracker, test, sleeping, now);
+        return ProcessList.computeNextPssTime(procState, mProcStateMemTracker, test, sleeping, now,
+                // Cap the Pss time to make sure no Pss is collected during the very few
+                // minutes after the system is boot, given the system is already busy.
+                Math.max(mService.mBootCompletedTimestamp, mService.mLastIdleTime)
+                + mService.mConstants.FULL_PSS_MIN_INTERVAL);
     }
 
     private static void commitNextPssTime(ProcStateMemTracker tracker) {
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/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..d65c7c2c 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
@@ -189,6 +189,8 @@
 
     private final AtomicBoolean mEnableCsd = new AtomicBoolean(false);
 
+    private final AtomicBoolean mForceCsdProperty = new AtomicBoolean(false);
+
     private final Object mCsdAsAFeatureLock = new Object();
 
     @GuardedBy("mCsdAsAFeatureLock")
@@ -375,9 +377,21 @@
         }
     }
 
+    private boolean updateCsdForTestApi() {
+        if (mForceCsdProperty.get() != SystemProperties.getBoolean(
+                SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE, false)) {
+            updateCsdEnabled("SystemPropertiesChangeCallback");
+        }
+
+        return mEnableCsd.get();
+    }
+
     float getCsd() {
         if (!mEnableCsd.get()) {
-            return -1.f;
+            // since this will only be called by a test api enable csd if system property is set
+            if (!updateCsdForTestApi()) {
+                return -1.f;
+            }
         }
 
         final ISoundDose soundDose = mSoundDose.get();
@@ -396,7 +410,10 @@
 
     void setCsd(float csd) {
         if (!mEnableCsd.get()) {
-            return;
+            // since this will only be called by a test api enable csd if system property is set
+            if (!updateCsdForTestApi()) {
+                return;
+            }
         }
 
         SoundDoseRecord[] doseRecordsArray;
@@ -430,7 +447,10 @@
 
     void resetCsdTimeouts() {
         if (!mEnableCsd.get()) {
-            return;
+            // since this will only be called by a test api enable csd if system property is set
+            if (!updateCsdForTestApi()) {
+                return;
+            }
         }
 
         synchronized (mCsdStateLock) {
@@ -440,7 +460,10 @@
 
     void forceUseFrameworkMel(boolean useFrameworkMel) {
         if (!mEnableCsd.get()) {
-            return;
+            // since this will only be called by a test api enable csd if system property is set
+            if (!updateCsdForTestApi()) {
+                return;
+            }
         }
 
         final ISoundDose soundDose = mSoundDose.get();
@@ -458,7 +481,10 @@
 
     void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) {
         if (!mEnableCsd.get()) {
-            return;
+            // since this will only be called by a test api enable csd if system property is set
+            if (!updateCsdForTestApi()) {
+                return;
+            }
         }
 
         final ISoundDose soundDose = mSoundDose.get();
@@ -488,7 +514,7 @@
         try {
             return soundDose.isSoundDoseHalSupported();
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception while forcing CSD computation on all devices", e);
+            Log.e(TAG, "Exception while querying the csd enabled status", e);
         }
         return false;
     }
@@ -544,7 +570,7 @@
             audioDeviceCategory.csdCompatible = isHeadphone;
             soundDose.setAudioDeviceCategory(audioDeviceCategory);
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception while forcing the internal MEL computation", e);
+            Log.e(TAG, "Exception while setting the audio device category", e);
         }
     }
 
@@ -894,7 +920,7 @@
                 mCachedAudioDeviceCategories.clear();
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception while forcing the internal MEL computation", e);
+            Log.e(TAG, "Exception while initializing the cached audio device categories", e);
         }
 
         synchronized (mCsdAsAFeatureLock) {
@@ -991,19 +1017,20 @@
     }
 
     private void updateCsdEnabled(String caller) {
-        boolean csdForce = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE, false);
+        mForceCsdProperty.set(SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE,
+                false));
         // we are using the MCC overlaid legacy flag used for the safe volume enablement
         // to determine whether the MCC enforces any safe hearing standard.
         boolean mccEnforcedSafeMedia = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_safe_media_volume_enabled);
         boolean csdEnable = mContext.getResources().getBoolean(
                 R.bool.config_safe_sound_dosage_enabled);
-        boolean newEnabledCsd = (mccEnforcedSafeMedia && csdEnable) || csdForce;
+        boolean newEnabledCsd = (mccEnforcedSafeMedia && csdEnable) || mForceCsdProperty.get();
 
         synchronized (mCsdAsAFeatureLock) {
             if (!mccEnforcedSafeMedia && csdEnable) {
                 mIsCsdAsAFeatureAvailable = true;
-                newEnabledCsd = mIsCsdAsAFeatureEnabled || csdForce;
+                newEnabledCsd = mIsCsdAsAFeatureEnabled || mForceCsdProperty.get();
                 Log.v(TAG, caller + ": CSD as a feature is not enforced and enabled: "
                         + newEnabledCsd);
             } else {
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 4538cad..1760bb3 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -41,6 +41,7 @@
 import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IAuthService;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.biometrics.IBiometricPromptStatusListener;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IInvalidationCallback;
@@ -357,6 +358,18 @@
         }
 
         @Override
+        public void registerBiometricPromptStatusListener(
+                IBiometricPromptStatusListener listener) throws RemoteException {
+            checkInternalPermission();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mBiometricService.registerBiometricPromptStatusListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void invalidateAuthenticatorIds(int userId, int fromSensorId,
                 IInvalidationCallback callback) throws RemoteException {
             checkInternalPermission();
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 1898b80..9569f23 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -41,6 +41,7 @@
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.biometrics.IBiometricPromptStatusListener;
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -88,6 +89,7 @@
 import java.util.Map;
 import java.util.Random;
 import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Supplier;
 
@@ -105,6 +107,8 @@
     @VisibleForTesting
     final SettingObserver mSettingObserver;
     private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
+    private final ConcurrentLinkedQueue<BiometricPromptStatusListener>
+            mBiometricPromptStatusListeners;
     private final Random mRandom = new Random();
     @NonNull private final Supplier<Long> mRequestCounter;
     @NonNull private final BiometricContext mBiometricContext;
@@ -425,6 +429,42 @@
         }
     }
 
+    final class BiometricPromptStatusListener implements IBinder.DeathRecipient {
+        private final IBiometricPromptStatusListener mBiometricPromptStatusListener;
+
+        BiometricPromptStatusListener(IBiometricPromptStatusListener callback) {
+            mBiometricPromptStatusListener = callback;
+        }
+
+        void notifyBiometricPromptShowing() {
+            try {
+                mBiometricPromptStatusListener.onBiometricPromptShowing();
+            } catch (DeadObjectException e) {
+                Slog.w(TAG, "Death while invoking notifyHandleAuthenticate", e);
+                mBiometricPromptStatusListeners.remove(this);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to invoke notifyHandleAuthenticate", e);
+            }
+        }
+
+        void notifyBiometricPromptIdle() {
+            try {
+                mBiometricPromptStatusListener.onBiometricPromptIdle();
+            } catch (DeadObjectException e) {
+                Slog.w(TAG, "Death while invoking notifyDialogDismissed", e);
+                mBiometricPromptStatusListeners.remove(this);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to invoke notifyDialogDismissed", e);
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            Slog.e(TAG, "Biometric prompt callback binder died");
+            mBiometricPromptStatusListeners.remove(this);
+        }
+    }
+
     // Receives events from individual biometric sensors.
     private IBiometricSensorReceiver createBiometricSensorReceiver(final long requestId) {
         return new IBiometricSensorReceiver.Stub() {
@@ -705,6 +745,22 @@
 
         @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
         @Override // Binder call
+        public void registerBiometricPromptStatusListener(IBiometricPromptStatusListener callback) {
+            super.registerBiometricPromptStatusListener_enforcePermission();
+
+            BiometricPromptStatusListener biometricPromptStatusListener =
+                    new BiometricPromptStatusListener(callback);
+            mBiometricPromptStatusListeners.add(biometricPromptStatusListener);
+
+            if (mAuthSession != null) {
+                biometricPromptStatusListener.notifyBiometricPromptShowing();
+            } else {
+                biometricPromptStatusListener.notifyBiometricPromptIdle();
+            }
+        }
+
+        @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+        @Override // Binder call
         public void invalidateAuthenticatorIds(int userId, int fromSensorId,
                 IInvalidationCallback callback) {
 
@@ -1044,6 +1100,7 @@
         mDevicePolicyManager = mInjector.getDevicePolicyManager(context);
         mImpl = new BiometricServiceWrapper();
         mEnabledOnKeyguardCallbacks = new ArrayList<>();
+        mBiometricPromptStatusListeners = new ConcurrentLinkedQueue<>();
         mSettingObserver = mInjector.getSettingObserver(context, mHandler,
                 mEnabledOnKeyguardCallbacks);
         mRequestCounter = mInjector.getRequestGenerator();
@@ -1158,6 +1215,7 @@
             if (finished) {
                 Slog.d(TAG, "handleOnError: AuthSession finished");
                 mAuthSession = null;
+                notifyAuthSessionChanged();
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "RemoteException", e);
@@ -1186,6 +1244,7 @@
 
         session.onDialogDismissed(reason, credentialAttestation);
         mAuthSession = null;
+        notifyAuthSessionChanged();
     }
 
     private void handleOnTryAgainPressed(long requestId) {
@@ -1235,6 +1294,7 @@
         final boolean finished = session.onClientDied();
         if (finished) {
             mAuthSession = null;
+            notifyAuthSessionChanged();
         }
     }
 
@@ -1349,6 +1409,16 @@
         });
     }
 
+    private void notifyAuthSessionChanged() {
+        for (BiometricPromptStatusListener listener : mBiometricPromptStatusListeners) {
+            if (mAuthSession == null) {
+                listener.notifyBiometricPromptIdle();
+            } else {
+                listener.notifyBiometricPromptShowing();
+            }
+        }
+    }
+
     /**
      * handleAuthenticate() (above) which is called from BiometricPrompt determines which
      * modality/modalities to start authenticating with. authenticateInternal() should only be
@@ -1386,6 +1456,7 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "RemoteException", e);
         }
+        notifyAuthSessionChanged();
     }
 
     private void handleCancelAuthentication(long requestId) {
@@ -1400,6 +1471,7 @@
         if (finished) {
             Slog.d(TAG, "handleCancelAuthentication: AuthSession finished");
             mAuthSession = null;
+            notifyAuthSessionChanged();
         }
     }
 
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/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d372f30..0689478 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -160,6 +160,7 @@
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.layout.Layout;
 import com.android.server.display.mode.DisplayModeDirector;
+import com.android.server.display.notifications.DisplayNotificationManager;
 import com.android.server.display.utils.SensorUtils;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.utils.FoldSettingProvider;
@@ -522,6 +523,8 @@
 
     private final DisplayManagerFlags mFlags;
 
+    private final DisplayNotificationManager mDisplayNotificationManager;
+
     /**
      * Applications use {@link android.view.Display#getRefreshRate} and
      * {@link android.view.Display.Mode#getRefreshRate} to know what is the display refresh rate.
@@ -555,6 +558,7 @@
         mInjector = injector;
         mContext = context;
         mFlags = injector.getFlags();
+        mDisplayNotificationManager = new DisplayNotificationManager(mFlags, mContext);
         mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
@@ -650,6 +654,7 @@
             }
             mDisplayModeDirector.onBootCompleted();
             mLogicalDisplayMapper.onBootCompleted();
+            mDisplayNotificationManager.onBootCompleted();
         }
     }
 
@@ -784,6 +789,10 @@
         }
     }
 
+    DisplayNotificationManager getDisplayNotificationManager() {
+        return mDisplayNotificationManager;
+    }
+
     private void loadStableDisplayValuesLocked() {
         final Point size = mPersistentDataStore.getStableDisplaySize();
         if (size.x > 0 && size.y > 0) {
@@ -1776,7 +1785,8 @@
         synchronized (mSyncRoot) {
             // main display adapter
             registerDisplayAdapterLocked(mInjector.getLocalDisplayAdapter(mSyncRoot, mContext,
-                    mHandler, mDisplayDeviceRepo, mFlags));
+                    mHandler, mDisplayDeviceRepo, mFlags,
+                    mDisplayNotificationManager));
 
             // Standalone VR devices rely on a virtual display as their primary display for
             // 2D UI. We register virtual display adapter along side the main display adapter
@@ -3191,9 +3201,10 @@
 
         LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
                 Handler handler, DisplayAdapter.Listener displayAdapterListener,
-                DisplayManagerFlags flags) {
+                DisplayManagerFlags flags,
+                DisplayNotificationManager displayNotificationManager) {
             return new LocalDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
-                    flags);
+                    flags, displayNotificationManager);
         }
 
         long getDefaultDisplayDelayTimeout() {
diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
index 9b022d8..d97c8e7 100644
--- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
+++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
@@ -30,6 +30,8 @@
 
 class DisplayManagerShellCommand extends ShellCommand {
     private static final String TAG = "DisplayManagerShellCommand";
+    private static final String NOTIFICATION_TYPES =
+            "on-hotplug-error, on-link-training-failure, on-cable-dp-incapable";
 
     private final DisplayManagerService mService;
     private final DisplayManagerFlags mFlags;
@@ -46,6 +48,10 @@
         }
         final PrintWriter pw = getOutPrintWriter();
         switch(cmd) {
+            case "show-notification":
+                return showNotification();
+            case "cancel-notifications":
+                return cancelNotifications();
             case "set-brightness":
                 return setBrightness();
             case "reset-brightness-configuration":
@@ -102,6 +108,10 @@
         pw.println("  help");
         pw.println("    Print this help text.");
         pw.println();
+        pw.println("  show-notification NOTIFICATION_TYPE");
+        pw.println("    Show notification for one of the following types: " + NOTIFICATION_TYPES);
+        pw.println("  cancel-notifications");
+        pw.println("    Cancel notifications.");
         pw.println("  set-brightness BRIGHTNESS");
         pw.println("    Sets the current brightness to BRIGHTNESS (a number between 0 and 1).");
         pw.println("  reset-brightness-configuration");
@@ -172,6 +182,39 @@
         return 0;
     }
 
+    private int showNotification() {
+        final String notificationType = getNextArg();
+        if (notificationType == null) {
+            getErrPrintWriter().println("Error: no notificationType specified, use one of: "
+                                                + NOTIFICATION_TYPES);
+            return 1;
+        }
+
+        switch(notificationType) {
+            case "on-hotplug-error":
+                mService.getDisplayNotificationManager().onHotplugConnectionError();
+                break;
+            case "on-link-training-failure":
+                mService.getDisplayNotificationManager().onDisplayPortLinkTrainingFailure();
+                break;
+            case "on-cable-dp-incapable":
+                mService.getDisplayNotificationManager().onCableNotCapableDisplayPort();
+                break;
+            default:
+                getErrPrintWriter().println(
+                        "Error: unexpected notification type=" + notificationType + ", use one of: "
+                                + NOTIFICATION_TYPES);
+                return 1;
+        }
+
+        return 0;
+    }
+
+    private int cancelNotifications() {
+        mService.getDisplayNotificationManager().cancelNotifications();
+        return 0;
+    }
+
     private int setBrightness() {
         String brightnessText = getNextArg();
         if (brightnessText == null) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 0a1f316..e5d38cb 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -22,9 +22,8 @@
 import android.app.ActivityThread;
 import android.content.Context;
 import android.content.res.Resources;
-import android.hardware.display.DisplayManagerInternal;
-import android.hardware.display.DisplayManagerInternal.DisplayOffloader;
 import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession;
+import android.hardware.display.DisplayManagerInternal.DisplayOffloader;
 import android.hardware.sidekick.SidekickInternal;
 import android.os.Build;
 import android.os.Handler;
@@ -52,6 +51,7 @@
 import com.android.server.LocalServices;
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.mode.DisplayModeDirector;
+import com.android.server.display.notifications.DisplayNotificationManager;
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LogicalLight;
 
@@ -86,18 +86,25 @@
 
     private final DisplayManagerFlags mFlags;
 
+    private final DisplayNotificationManager mDisplayNotificationManager;
+
     private Context mOverlayContext;
 
     // Called with SyncRoot lock held.
     LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context,
-            Handler handler, Listener listener, DisplayManagerFlags flags) {
-        this(syncRoot, context, handler, listener, flags, new Injector());
+            Handler handler, Listener listener, DisplayManagerFlags flags,
+            DisplayNotificationManager displayNotificationManager) {
+        this(syncRoot, context, handler, listener, flags, displayNotificationManager,
+                new Injector());
     }
 
     @VisibleForTesting
     LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler,
-            Listener listener, DisplayManagerFlags flags, Injector injector) {
+            Listener listener, DisplayManagerFlags flags,
+            DisplayNotificationManager displayNotificationManager,
+            Injector injector) {
         super(syncRoot, context, handler, listener, TAG);
+        mDisplayNotificationManager = displayNotificationManager;
         mInjector = injector;
         mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
         mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport();
@@ -1454,6 +1461,8 @@
                         + "timestampNanos=" + timestampNanos
                         + ", connectionError=" + connectionError + ")");
             }
+
+            mDisplayNotificationManager.onHotplugConnectionError();
         }
 
         @Override
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 d5382cb..7050c5a 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -47,6 +47,10 @@
             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);
@@ -55,6 +59,14 @@
             Flags.FLAG_ENABLE_MODE_LIMIT_FOR_EXTERNAL_DISPLAY,
             Flags::enableModeLimitForExternalDisplay);
 
+    private final FlagState mConnectedDisplayErrorHandlingFlagState = new FlagState(
+            Flags.FLAG_ENABLE_CONNECTED_DISPLAY_ERROR_HANDLING,
+            Flags::enableConnectedDisplayErrorHandling);
+
+    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() {
         return mConnectedDisplayManagementFlagState.isEnabled();
@@ -76,6 +88,13 @@
         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 isExternalDisplayLimitModeEnabled();
@@ -108,6 +127,15 @@
         return mDisplayOffloadFlagState.isEnabled();
     }
 
+    /** Returns whether error notifications for connected displays are enabled on not */
+    public boolean isConnectedDisplayErrorHandlingEnabled() {
+        return mConnectedDisplayErrorHandlingFlagState.isEnabled();
+    }
+
+    public boolean isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled() {
+        return mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState.isEnabled();
+    }
+
     private static class FlagState {
 
         private final String mName;
@@ -121,7 +149,6 @@
             mFlagFunction = flagFunction;
         }
 
-        // TODO(b/297159910): Simplify using READ-ONLY flags when available.
         private boolean isEnabled() {
             if (mEnabledSet) {
                 if (DEBUG) {
@@ -138,19 +165,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..a85e10d 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,19 @@
     bug: "299521647"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "enable_connected_display_error_handling"
+    namespace: "display_manager"
+    description: "Feature flag for connected display error handling"
+    bug: "283461472"
+    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/display/notifications/ConnectedDisplayUsbErrorsDetector.java b/services/core/java/com/android/server/display/notifications/ConnectedDisplayUsbErrorsDetector.java
new file mode 100644
index 0000000..f683e81
--- /dev/null
+++ b/services/core/java/com/android/server/display/notifications/ConnectedDisplayUsbErrorsDetector.java
@@ -0,0 +1,132 @@
+/*
+ * 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.notifications;
+
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE;
+import static android.hardware.usb.DisplayPortAltModeInfo.LINK_TRAINING_STATUS_FAILURE;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.hardware.usb.DisplayPortAltModeInfo;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbManager.DisplayPortAltModeInfoListener;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.feature.DisplayManagerFlags;
+
+/**
+ * Detects usb issues related to an external display connected.
+ */
+public class ConnectedDisplayUsbErrorsDetector implements DisplayPortAltModeInfoListener {
+    private static final String TAG = "ConnectedDisplayUsbErrorsDetector";
+
+    /**
+     * Dependency injection for {@link ConnectedDisplayUsbErrorsDetector}.
+     */
+    public interface Injector {
+
+        /**
+         * @return {@link UsbManager} service.
+         */
+        UsbManager getUsbManager();
+    }
+
+    /**
+     * USB errors listener
+     */
+    public interface Listener {
+
+        /**
+         * Link training failure callback.
+         */
+        void onDisplayPortLinkTrainingFailure();
+
+        /**
+         * DisplayPort capable device plugged-in, but cable is not supporting DisplayPort.
+         */
+        void onCableNotCapableDisplayPort();
+    }
+
+    private Listener mListener;
+    private final Injector mInjector;
+    private final Context mContext;
+    private final boolean mIsConnectedDisplayErrorHandlingEnabled;
+
+    ConnectedDisplayUsbErrorsDetector(@NonNull final DisplayManagerFlags flags,
+            @NonNull final Context context) {
+        this(flags, context, () -> context.getSystemService(UsbManager.class));
+    }
+
+    @VisibleForTesting
+    ConnectedDisplayUsbErrorsDetector(@NonNull final DisplayManagerFlags flags,
+            @NonNull final Context context, @NonNull final Injector injector) {
+        mContext = context;
+        mInjector = injector;
+        mIsConnectedDisplayErrorHandlingEnabled =
+                flags.isConnectedDisplayErrorHandlingEnabled();
+    }
+
+    /** Register listener for usb error events. */
+    @SuppressLint("AndroidFrameworkRequiresPermission")
+    void registerListener(final Listener listener) {
+        if (!mIsConnectedDisplayErrorHandlingEnabled) {
+            return;
+        }
+
+        final var usbManager = mInjector.getUsbManager();
+        if (usbManager == null) {
+            Slog.e(TAG, "UsbManager is null");
+            return;
+        }
+
+        mListener = listener;
+
+        try {
+            usbManager.registerDisplayPortAltModeInfoListener(mContext.getMainExecutor(), this);
+        } catch (IllegalStateException e) {
+            Slog.e(TAG, "Failed to register listener", e);
+        }
+    }
+
+    /**
+     * Callback upon changes in {@link DisplayPortAltModeInfo}.
+     * @param portId    String describing the {@link android.hardware.usb.UsbPort} that was changed.
+     * @param info      New {@link DisplayPortAltModeInfo} for the corresponding portId.
+     */
+    @Override
+    public void onDisplayPortAltModeInfoChanged(@NonNull String portId,
+            @NonNull DisplayPortAltModeInfo info) {
+        if (mListener == null) {
+            return;
+        }
+
+        if (DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED == info.getPartnerSinkStatus()
+                && DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE == info.getCableStatus()
+        ) {
+            mListener.onCableNotCapableDisplayPort();
+            return;
+        }
+
+        if (LINK_TRAINING_STATUS_FAILURE == info.getLinkTrainingStatus()) {
+            mListener.onDisplayPortLinkTrainingFailure();
+            return;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/display/notifications/DisplayNotificationManager.java b/services/core/java/com/android/server/display/notifications/DisplayNotificationManager.java
new file mode 100644
index 0000000..5cdef38
--- /dev/null
+++ b/services/core/java/com/android/server/display/notifications/DisplayNotificationManager.java
@@ -0,0 +1,205 @@
+/*
+ * 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.notifications;
+
+import static android.app.Notification.COLOR_DEFAULT;
+import static com.android.internal.notification.SystemNotificationChannels.ALERTS;
+
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.feature.DisplayManagerFlags;
+
+/**
+ * Manages notifications for {@link com.android.server.display.DisplayManagerService}.
+ */
+public class DisplayNotificationManager implements ConnectedDisplayUsbErrorsDetector.Listener {
+    /** Dependency injection interface for {@link DisplayNotificationManager} */
+    public interface Injector {
+        /** Get {@link NotificationManager} service or null if not available. */
+        @Nullable
+        NotificationManager getNotificationManager();
+
+        /** Get {@link ConnectedDisplayUsbErrorsDetector} or null if not available. */
+        @Nullable
+        ConnectedDisplayUsbErrorsDetector getUsbErrorsDetector();
+    }
+
+    private static final String TAG = "DisplayNotificationManager";
+    private static final String NOTIFICATION_GROUP_NAME = TAG;
+    private static final String DISPLAY_NOTIFICATION_TAG = TAG;
+    private static final int DISPLAY_NOTIFICATION_ID = 1;
+    private static final long NOTIFICATION_TIMEOUT_MILLISEC = 30000L;
+
+    private final Injector mInjector;
+    private final Context mContext;
+    private final boolean mConnectedDisplayErrorHandlingEnabled;
+    private NotificationManager mNotificationManager;
+    private ConnectedDisplayUsbErrorsDetector mConnectedDisplayUsbErrorsDetector;
+
+    public DisplayNotificationManager(final DisplayManagerFlags flags, final Context context) {
+        this(flags, context, new Injector() {
+            @Nullable
+            @Override
+            public NotificationManager getNotificationManager() {
+                return context.getSystemService(NotificationManager.class);
+            }
+
+            @Nullable
+            @Override
+            public ConnectedDisplayUsbErrorsDetector getUsbErrorsDetector() {
+                return new ConnectedDisplayUsbErrorsDetector(flags, context);
+            }
+        });
+    }
+
+    @VisibleForTesting
+    DisplayNotificationManager(final DisplayManagerFlags flags, final Context context,
+            final Injector injector) {
+        mConnectedDisplayErrorHandlingEnabled = flags.isConnectedDisplayErrorHandlingEnabled();
+        mContext = context;
+        mInjector = injector;
+    }
+
+    /**
+     * Initialize services, which may be not yet published during boot.
+     * see {@link android.os.ServiceManager.ServiceNotFoundException}.
+     */
+    public void onBootCompleted() {
+        mNotificationManager = mInjector.getNotificationManager();
+        if (mNotificationManager == null) {
+            Slog.e(TAG, "onBootCompleted: NotificationManager is null");
+            return;
+        }
+
+        mConnectedDisplayUsbErrorsDetector = mInjector.getUsbErrorsDetector();
+        if (mConnectedDisplayUsbErrorsDetector != null) {
+            mConnectedDisplayUsbErrorsDetector.registerListener(this);
+        }
+    }
+
+    /**
+     * Display error notification upon DisplayPort link training failure.
+     */
+    @Override
+    public void onDisplayPortLinkTrainingFailure() {
+        if (!mConnectedDisplayErrorHandlingEnabled) {
+            Slog.d(TAG, "onDisplayPortLinkTrainingFailure:"
+                                + " mConnectedDisplayErrorHandlingEnabled is false");
+            return;
+        }
+
+        sendErrorNotification(createErrorNotification(
+                R.string.connected_display_unavailable_notification_title,
+                R.string.connected_display_unavailable_notification_content));
+    }
+
+    /**
+     * Display error notification upon cable not capable of DisplayPort connected to a device
+     * capable of DisplayPort.
+     */
+    @Override
+    public void onCableNotCapableDisplayPort() {
+        if (!mConnectedDisplayErrorHandlingEnabled) {
+            Slog.d(TAG, "onCableNotCapableDisplayPort:"
+                                + " mConnectedDisplayErrorHandlingEnabled is false");
+            return;
+        }
+
+        sendErrorNotification(createErrorNotification(
+                R.string.connected_display_cable_dont_support_displays_notification_title,
+                R.string.connected_display_cable_dont_support_displays_notification_content));
+    }
+
+    /**
+     * Send notification about hotplug connection error.
+     */
+    public void onHotplugConnectionError() {
+        if (!mConnectedDisplayErrorHandlingEnabled) {
+            Slog.d(TAG, "onHotplugConnectionError:"
+                                + " mConnectedDisplayErrorHandlingEnabled is false");
+            return;
+        }
+
+        sendErrorNotification(createErrorNotification(
+                R.string.connected_display_unavailable_notification_title,
+                R.string.connected_display_unavailable_notification_content));
+    }
+
+    /**
+     * Cancel sent notifications.
+     */
+    public void cancelNotifications() {
+        if (mNotificationManager == null) {
+            Slog.e(TAG, "Can't cancelNotifications: NotificationManager is null");
+            return;
+        }
+
+        mNotificationManager.cancel(DISPLAY_NOTIFICATION_TAG, DISPLAY_NOTIFICATION_ID);
+    }
+
+    /**
+     * Send generic error notification.
+     */
+    @SuppressLint("AndroidFrameworkRequiresPermission")
+    private void sendErrorNotification(final Notification notification) {
+        if (mNotificationManager == null) {
+            Slog.e(TAG, "Can't sendErrorNotification: NotificationManager is null");
+            return;
+        }
+
+        mNotificationManager.notify(DISPLAY_NOTIFICATION_TAG, DISPLAY_NOTIFICATION_ID,
+                notification);
+    }
+
+    /**
+     * @return a newly built notification about an issue with connected display.
+     */
+    private Notification createErrorNotification(final int titleId, final int messageId) {
+        final Resources resources = mContext.getResources();
+        final CharSequence title = resources.getText(titleId);
+        final CharSequence message = resources.getText(messageId);
+
+        int color = COLOR_DEFAULT;
+        try (var attrs = mContext.obtainStyledAttributes(new int[]{R.attr.colorError})) {
+            color = attrs.getColor(0, color);
+        } catch (Resources.NotFoundException e) {
+            Slog.e(TAG, "colorError attribute is not found: " + e.getMessage());
+        }
+
+        return new Notification.Builder(mContext, ALERTS)
+                .setGroup(NOTIFICATION_GROUP_NAME)
+                .setSmallIcon(R.drawable.usb_cable_unknown_issue)
+                .setWhen(0)
+                .setTimeoutAfter(NOTIFICATION_TIMEOUT_MILLISEC)
+                .setOngoing(false)
+                .setTicker(title)
+                .setColor(color)
+                .setContentTitle(title)
+                .setContentText(message)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setCategory(Notification.CATEGORY_ERROR)
+                .build();
+    }
+}
diff --git a/services/core/java/com/android/server/feature/Android.bp b/services/core/java/com/android/server/feature/Android.bp
new file mode 100644
index 0000000..067288d
--- /dev/null
+++ b/services/core/java/com/android/server/feature/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+    name: "dropbox_flags",
+    package: "com.android.server.feature.flags",
+    srcs: [
+        "dropbox_flags.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "dropbox_flags_lib",
+    aconfig_declarations: "dropbox_flags",
+}
diff --git a/services/core/java/com/android/server/feature/dropbox_flags.aconfig b/services/core/java/com/android/server/feature/dropbox_flags.aconfig
new file mode 100644
index 0000000..fee4bf3
--- /dev/null
+++ b/services/core/java/com/android/server/feature/dropbox_flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.feature.flags"
+
+flag{
+    name: "enable_read_dropbox_permission"
+    namespace: "preload_safety"
+    description: "Feature flag for permission to Read dropbox data"
+    bug: "287512663"
+}
\ No newline at end of file
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/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 429db5e..c28a68b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -4951,6 +4951,11 @@
         AudioDeviceAttributes attributes = new AudioDeviceAttributes(
                 AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_EARC, "", "",
                 new ArrayList<AudioProfile>(), audioDescriptors);
+        // Set SAM to ON whenever CEC is disabled. Failure to do so may result in the absence
+        // of sound when CEC is disabled and eARC is enabled due to SAM being in the off state.
+        if (!isCecControlEnabled()) {
+            setSystemAudioActivated(true);
+        }
         getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
     }
 
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/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index d4578dc..4851a81 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -486,9 +486,12 @@
                 Settings.Secure.DEFAULT_INPUT_METHOD,
                 userId);
         if (!TextUtils.isEmpty(currentInputMethod)) {
-            String inputMethodPkgName = ComponentName
-                    .unflattenFromString(currentInputMethod)
-                    .getPackageName();
+            ComponentName componentName = ComponentName.unflattenFromString(currentInputMethod);
+            if (componentName == null) {
+                Slog.d(TAG, "inValid input method");
+                return false;
+            }
+            String inputMethodPkgName = componentName.getPackageName();
             int inputMethodUid = getPackageUid(inputMethodPkgName, userId);
             return inputMethodUid >= 0 && UserHandle.isSameApp(Binder.getCallingUid(),
                     inputMethodUid);
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 c9528d8..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()
@@ -2779,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/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 87c3067..837b761 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2532,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);
         }
 
@@ -3369,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) {
@@ -5730,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;
             }
@@ -5762,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
@@ -8612,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;
@@ -8757,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..7d822b5 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -34,6 +34,7 @@
 import android.app.AppOpsManager;
 import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.DataLoaderType;
+import android.content.pm.Flags;
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
@@ -922,7 +923,7 @@
         // 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()) {
+        if (isInstallFromAdb() && Flags.useArtServiceV2()) {
             var externalProfileErrors = new LinkedHashSet<String>();
             for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) {
                 for (DexContainerFileDexoptResult fileResult :
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/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ddc8369..68aa93d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4501,6 +4501,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 +4523,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 +4555,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 +6949,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/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 68a8e40..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;
@@ -1559,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);
         }
@@ -3785,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 {
@@ -3834,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) {
@@ -3852,6 +3855,7 @@
 
                 updateUserIds();
                 upgradeIfNecessaryLP();
+                updateUsersWithFeatureFlags(guestRestrictionsArePresentOnUserListXml);
             } catch (Exception e) {
                 // Remove corrupted file and retry.
                 file.failRead(fin, e);
@@ -3877,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()}.
      */
@@ -4393,9 +4415,24 @@
             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),
@@ -4471,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()];
@@ -4620,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) {
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/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index d16a812..d804e01 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -444,7 +444,7 @@
 
         updateApplicationInfo(info, flags, state);
 
-        initForUser(info, pkg, userId);
+        initForUser(info, pkg, userId, state);
 
         // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up
         PackageStateUnserialized pkgState = pkgSetting.getTransientState();
@@ -690,7 +690,7 @@
         info.splitDependencies = pkg.getSplitDependencies().size() == 0
                 ? null : pkg.getSplitDependencies();
 
-        initForUser(info, pkg, userId);
+        initForUser(info, pkg, userId, state);
 
         info.primaryCpuAbi = pkgSetting.getPrimaryCpuAbi();
         info.secondaryCpuAbi = pkgSetting.getSecondaryCpuAbi();
@@ -1006,7 +1006,7 @@
     }
 
     private static void initForUser(ApplicationInfo output, AndroidPackage input,
-            @UserIdInt int userId) {
+            @UserIdInt int userId, PackageUserStateInternal state) {
         PackageImpl pkg = ((PackageImpl) input);
         String packageName = input.getPackageName();
         output.uid = UserHandle.getUid(userId, UserHandle.getAppId(input.getUid()));
@@ -1016,6 +1016,13 @@
             return;
         }
 
+        if (android.content.pm.Flags.nullableDataDir()
+                && !state.isInstalled() && !state.dataExists()) {
+            // The data dir has been deleted
+            output.dataDir = null;
+            return;
+        }
+
         // For performance reasons, all these paths are built as strings
         if (userId == UserHandle.USER_SYSTEM) {
             output.credentialProtectedDataDir =
@@ -1050,7 +1057,7 @@
     // This duplicates the ApplicationInfo variant because it uses field assignment and the classes
     // don't inherit from each other, unfortunately. Consolidating logic would introduce overhead.
     private static void initForUser(InstrumentationInfo output, AndroidPackage input,
-            @UserIdInt int userId) {
+            @UserIdInt int userId, PackageUserStateInternal state) {
         PackageImpl pkg = ((PackageImpl) input);
         String packageName = input.getPackageName();
         if ("android".equals(packageName)) {
@@ -1058,6 +1065,13 @@
             return;
         }
 
+        if (android.content.pm.Flags.nullableDataDir()
+                && !state.isInstalled() && !state.dataExists()) {
+            // The data dir has been deleted
+            output.dataDir = null;
+            return;
+        }
+
         // For performance reasons, all these paths are built as strings
         if (userId == UserHandle.USER_SYSTEM) {
             output.credentialProtectedDataDir =
@@ -1089,12 +1103,23 @@
         }
     }
 
-    @NonNull
+    /**
+     * Returns the data dir of the app for the target user. Return null if the app isn't installed
+     * on the target user and doesn't have a data dir on the target user.
+     */
+    @Nullable
     public static File getDataDir(PackageStateInternal ps, int userId) {
         if ("android".equals(ps.getPackageName())) {
             return Environment.getDataSystemDirectory();
         }
 
+        if (android.content.pm.Flags.nullableDataDir()
+                && !ps.getUserStateOrDefault(userId).isInstalled()
+                && !ps.getUserStateOrDefault(userId).dataExists()) {
+            // The app has been uninstalled for the user and the data dir has been deleted
+            return null;
+        }
+
         if (ps.isDefaultToDeviceProtectedStorage()
                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
             return Environment.getDataUserDePackageDirectory(ps.getVolumeUuid(), userId,
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/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/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index bff6d50..6d580e9 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -39,8 +39,10 @@
 import android.speech.RecognitionService;
 import android.speech.SpeechRecognizer;
 import android.util.Slog;
+import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.modules.expresslog.Counter;
 import com.android.server.infra.AbstractPerUserSystemService;
 
 import java.util.HashMap;
@@ -64,6 +66,9 @@
     private final Map<Integer, Set<RemoteSpeechRecognitionService>> mRemoteServicesByUid =
             new HashMap<>();
 
+    @GuardedBy("mLock")
+    private final SparseIntArray mSessionCountByUid = new SparseIntArray();
+
     SpeechRecognitionManagerServiceImpl(
             @NonNull SpeechRecognitionManagerService master,
             @NonNull Object lock, @UserIdInt int userId) {
@@ -216,6 +221,7 @@
             service.shutdown(clientToken);
         }
         synchronized (mLock) {
+            decrementSessionCountForUidLocked(callingUid);
             if (!service.hasActiveSessions()) {
                 removeService(callingUid, service);
             }
@@ -239,6 +245,26 @@
         return ComponentName.unflattenFromString(serviceName);
     }
 
+    @GuardedBy("mLock")
+    private int getSessionCountByUidLocked(int uid) {
+        return mSessionCountByUid.get(uid, 0);
+    }
+
+    @GuardedBy("mLock")
+    private void incrementSessionCountForUidLocked(int uid) {
+        mSessionCountByUid.put(uid, mSessionCountByUid.get(uid, 0) + 1);
+    }
+
+    @GuardedBy("mLock")
+    private void decrementSessionCountForUidLocked(int uid) {
+        int newCount = mSessionCountByUid.get(uid, 1) - 1;
+        if (newCount > 0) {
+            mSessionCountByUid.put(uid, newCount);
+        } else {
+            mSessionCountByUid.delete(uid);
+        }
+    }
+
     private RemoteSpeechRecognitionService createService(
             int callingUid, ComponentName serviceComponent) {
         synchronized (mLock) {
@@ -247,6 +273,18 @@
 
             if (servicesForClient != null
                     && servicesForClient.size() >= MAX_CONCURRENT_CONNECTIONS_BY_CLIENT) {
+                Slog.w(TAG, "Number of remote services exceeded for uid: " + callingUid);
+                Counter.logIncrementWithUid(
+                        "speech_recognition.value_exceed_service_connections_count",
+                        callingUid);
+                return null;
+            }
+
+            if (getSessionCountByUidLocked(callingUid) >= MAX_CONCURRENT_CONNECTIONS_BY_CLIENT) {
+                Slog.w(TAG, "Number of sessions exceeded for uid: " + callingUid);
+                Counter.logIncrementWithUid(
+                        "speech_recognition.value_exceed_session_count",
+                        callingUid);
                 return null;
             }
 
@@ -262,6 +300,7 @@
                         Slog.i(TAG, "Reused existing connection to " + serviceComponent);
                     }
 
+                    incrementSessionCountForUidLocked(callingUid);
                     return existingService.get();
                 }
             }
@@ -282,6 +321,7 @@
                 Slog.i(TAG, "Creating a new connection to " + serviceComponent);
             }
 
+            incrementSessionCountForUidLocked(callingUid);
             return service;
         }
     }
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index a5c0fb3..cddc79d 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -1047,6 +1047,16 @@
                     // in use frontends when no available frontend has been found.
                     int priority = getFrontendHighestClientPriority(fr.getOwnerClientId());
                     if (currentLowestPriority > priority) {
+                        // we need to check the max used num if the target frontend type is not
+                        // currently in primary use (and simply blocked due to exclusive group)
+                        ClientProfile targetOwnerProfile = getClientProfile(fr.getOwnerClientId());
+                        int primaryFeId = targetOwnerProfile.getPrimaryFrontend();
+                        FrontendResource primaryFe = getFrontendResource(primaryFeId);
+                        if (fr.getType() != primaryFe.getType()
+                                && isFrontendMaxNumUseReached(fr.getType())) {
+                            continue;
+                        }
+                        // update the target frontend
                         inUseLowestPriorityFrHandle = fr.getHandle();
                         currentLowestPriority = priority;
                         isRequestFromSameProcess = (requestClient.getProcessId()
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java b/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
index e4f9607..a346216 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.os.VibrationEffect;
+import android.os.vibrator.Flags;
 import android.os.VibratorInfo;
 import android.os.vibrator.persistence.ParsedVibration;
 import android.os.vibrator.persistence.VibrationXmlParser;
@@ -127,6 +128,10 @@
                     VibrationXmlParser.VibrationXmlParserException,
                     XmlParserException,
                     XmlPullParserException {
+        if (!Flags.hapticFeedbackVibrationOemCustomizationEnabled()) {
+            Slog.d(TAG, "Haptic feedback customization feature is not enabled.");
+            return null;
+        }
         String customizationFile =
                 res.getString(
                         com.android.internal.R.string.config_hapticFeedbackCustomizationFile);
diff --git a/services/core/java/com/android/server/vibrator/OWNERS b/services/core/java/com/android/server/vibrator/OWNERS
index 9afa682..da5a476 100644
--- a/services/core/java/com/android/server/vibrator/OWNERS
+++ b/services/core/java/com/android/server/vibrator/OWNERS
@@ -1,6 +1,5 @@
 # Bug component: 345036
-
+khalilahmad@google.com
 lsandrade@google.com
 michaelwr@google.com
-sbowden@google.com
-khalilahmad@google.com
\ No newline at end of file
+roosa@google.com
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/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/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/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/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/Session.java b/services/core/java/com/android/server/wm/Session.java
index e6d4866..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()) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 882104a..f3fb7c4 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -703,6 +703,7 @@
         if (dc == null || mTargetDisplays.contains(dc)) return;
         mTargetDisplays.add(dc);
         addOnTopTasks(dc, mOnTopTasksStart);
+        mController.startPerfHintForDisplay(dc.mDisplayId);
     }
 
     /**
@@ -1391,7 +1392,6 @@
             dc.handleCompleteDeferredRemoval();
         }
         validateKeyguardOcclusion();
-        validateVisibility();
 
         mState = STATE_FINISHED;
         // Rotation change may be deferred while there is a display change transition, so check
@@ -2766,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 78afaa8..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
@@ -960,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.
@@ -1164,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..5b9acb2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowManagerFlags.java
@@ -0,0 +1,51 @@
+/*
+ * 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();
+
+    final boolean mWindowStateResizeItemFlag = Flags.windowStateResizeItemFlag();
+
+    /* 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 074b404..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() {
@@ -3100,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);
         }
     }
 
@@ -4629,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);
         }
@@ -4642,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) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4beec2b..726d4d7 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -186,6 +186,7 @@
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyCache;
+import android.app.servertransaction.WindowStateResizeItem;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Matrix;
@@ -3732,30 +3733,44 @@
 
         markRedrawForSyncReported();
 
-        try {
-            mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
-                    getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId,
-                    syncWithBuffers ? mSyncSeqId : -1, isDragResizing);
-            if (drawPending && prevRotation >= 0 && prevRotation != mLastReportedConfiguration
-                    .getMergedConfiguration().windowConfiguration.getRotation()) {
-                mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
-                ProtoLog.v(WM_DEBUG_ORIENTATION,
-                        "Requested redraw for orientation change: %s", this);
+        if (mWmService.mFlags.mWindowStateResizeItemFlag) {
+            getProcess().scheduleClientTransactionItem(
+                    WindowStateResizeItem.obtain(mClient, mClientWindowFrames, reportDraw,
+                            mLastReportedConfiguration, getCompatInsetsState(), forceRelayout,
+                            alwaysConsumeSystemBars, displayId,
+                            syncWithBuffers ? mSyncSeqId : -1, isDragResizing));
+            onResizePostDispatched(drawPending, prevRotation, displayId);
+        } else {
+            // TODO(b/301870955): cleanup after launch
+            try {
+                mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
+                        getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId,
+                        syncWithBuffers ? mSyncSeqId : -1, isDragResizing);
+                onResizePostDispatched(drawPending, prevRotation, displayId);
+            } catch (RemoteException e) {
+                // Cancel orientation change of this window to avoid blocking unfreeze display.
+                setOrientationChanging(false);
+                mLastFreezeDuration = (int) (SystemClock.elapsedRealtime()
+                        - mWmService.mDisplayFreezeTime);
+                Slog.w(TAG, "Failed to report 'resized' to " + this + " due to " + e);
             }
-
-            if (mWmService.mAccessibilityController.hasCallbacks()) {
-                mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(displayId);
-            }
-        } catch (RemoteException e) {
-            // Cancel orientation change of this window to avoid blocking unfreeze display.
-            setOrientationChanging(false);
-            mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
-                    - mWmService.mDisplayFreezeTime);
-            Slog.w(TAG, "Failed to report 'resized' to " + this + " due to " + e);
         }
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
+    private void onResizePostDispatched(boolean drawPending, int prevRotation, int displayId) {
+        if (drawPending && prevRotation >= 0 && prevRotation != mLastReportedConfiguration
+                .getMergedConfiguration().windowConfiguration.getRotation()) {
+            mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
+            ProtoLog.v(WM_DEBUG_ORIENTATION,
+                    "Requested redraw for orientation change: %s", this);
+        }
+
+        if (mWmService.mAccessibilityController.hasCallbacks()) {
+            mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(displayId);
+        }
+    }
+
     boolean inRelaunchingActivity() {
         return mActivityRecord != null && mActivityRecord.isRelaunching();
     }
diff --git a/services/core/jni/tvinput/JTvInputHal.cpp b/services/core/jni/tvinput/JTvInputHal.cpp
index 68e2c9a..c736617 100644
--- a/services/core/jni/tvinput/JTvInputHal.cpp
+++ b/services/core/jni/tvinput/JTvInputHal.cpp
@@ -147,7 +147,6 @@
 }
 
 int JTvInputHal::setTvMessageEnabled(int deviceId, int streamId, int type, bool enabled) {
-    Mutex::Autolock autoLock(&mLock);
     if (!mTvInput->setTvMessageEnabled(deviceId, streamId,
                                        static_cast<AidlTvMessageEventType>(type), enabled)
                  .isOk()) {
@@ -188,7 +187,7 @@
 
 void JTvInputHal::onDeviceAvailable(const TvInputDeviceInfoWrapper& info) {
     {
-        Mutex::Autolock autoLock(&mLock);
+        Mutex::Autolock autoLock(&mStreamLock);
         mConnections.add(info.deviceId, KeyedVector<int, Connection>());
     }
     JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -275,7 +274,7 @@
 
 void JTvInputHal::onDeviceUnavailable(int deviceId) {
     {
-        Mutex::Autolock autoLock(&mLock);
+        Mutex::Autolock autoLock(&mStreamLock);
         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
         for (size_t i = 0; i < connections.size(); ++i) {
             removeStream(deviceId, connections.keyAt(i));
@@ -289,7 +288,7 @@
 
 void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) {
     {
-        Mutex::Autolock autoLock(&mLock);
+        Mutex::Autolock autoLock(&mStreamLock);
         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
         for (size_t i = 0; i < connections.size(); ++i) {
             removeStream(deviceId, connections.keyAt(i));
@@ -330,7 +329,7 @@
 void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
     sp<BufferProducerThread> thread;
     {
-        Mutex::Autolock autoLock(&mLock);
+        Mutex::Autolock autoLock(&mStreamLock);
         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
         Connection& connection = connections.editValueFor(streamId);
         if (connection.mThread == NULL) {
diff --git a/services/core/jni/tvinput/JTvInputHal.h b/services/core/jni/tvinput/JTvInputHal.h
index b7b4b16..1d8d162 100644
--- a/services/core/jni/tvinput/JTvInputHal.h
+++ b/services/core/jni/tvinput/JTvInputHal.h
@@ -220,7 +220,6 @@
     void onTvMessage(int deviceId, int streamId, AidlTvMessageEventType type,
                      AidlTvMessage& message, signed char data[], int dataLength);
 
-    Mutex mLock;
     Mutex mStreamLock;
     jweak mThiz;
     sp<Looper> mLooper;
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 43e47d7..49af89b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -872,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;
@@ -4025,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);
             }
         }
+
     }
 
     /**
@@ -6476,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;
             }
@@ -7956,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(() -> {
@@ -9449,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);
             });
@@ -20119,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;
         }
     }
@@ -21393,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.");
@@ -21711,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;
     }
 
@@ -21785,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;
         }
@@ -23169,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";
@@ -23211,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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 49ad84a..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;
@@ -916,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".
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 486ddb4..a8902fc 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -1391,7 +1391,6 @@
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     private void addLegacyPackageDeviceServer(ServiceInfo serviceInfo, int userId) {
-        Log.d(TAG, "addLegacyPackageDeviceServer()" + userId);
         XmlResourceParser parser = null;
 
         try {
@@ -1529,7 +1528,6 @@
 
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     private void addUmpPackageDeviceServer(ServiceInfo serviceInfo, int userId) {
-        Log.d(TAG, "addUmpPackageDeviceServer()" + userId);
         XmlResourceParser parser = null;
 
         try {
diff --git a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
index c1d137f..93530cf 100644
--- a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
@@ -43,8 +43,7 @@
 
 @Keep
 class AccessCheckingService(context: Context) : SystemService(context) {
-    @Volatile
-    private lateinit var state: AccessState
+    @Volatile private lateinit var state: AccessState
     private val stateLock = Any()
 
     private val policy = AccessPolicy()
@@ -86,17 +85,22 @@
 
         val state = MutableAccessState()
         policy.initialize(
-            state, userIds, packageStates, disabledSystemPackageStates, knownPackages, isLeanback,
-            configPermissions, privilegedPermissionAllowlistPackages, permissionAllowlist,
+            state,
+            userIds,
+            packageStates,
+            disabledSystemPackageStates,
+            knownPackages,
+            isLeanback,
+            configPermissions,
+            privilegedPermissionAllowlistPackages,
+            permissionAllowlist,
             implicitToSourcePermissions
         )
         persistence.initialize()
         persistence.read(state)
         this.state = state
 
-        mutateState {
-            with(policy) { onInitialized() }
-        }
+        mutateState { with(policy) { onInitialized() } }
 
         appOpService.initialize()
         permissionService.initialize()
@@ -106,40 +110,40 @@
         get() = PackageManager.FEATURE_LEANBACK in availableFeatures
 
     private val SystemConfig.privilegedPermissionAllowlistPackages: IndexedListSet<String>
-        get() = MutableIndexedListSet<String>().apply {
-            this += "android"
-            if (PackageManager.FEATURE_AUTOMOTIVE in availableFeatures) {
-                // Note that SystemProperties.get(String, String) forces returning an empty string
-                // even if we pass null for the def parameter.
-                val carServicePackage = SystemProperties.get("ro.android.car.carservice.package")
-                if (carServicePackage.isNotEmpty()) {
-                    this += carServicePackage
+        get() =
+            MutableIndexedListSet<String>().apply {
+                this += "android"
+                if (PackageManager.FEATURE_AUTOMOTIVE in availableFeatures) {
+                    // Note that SystemProperties.get(String, String) forces returning an empty
+                    // string
+                    // even if we pass null for the def parameter.
+                    val carServicePackage =
+                        SystemProperties.get("ro.android.car.carservice.package")
+                    if (carServicePackage.isNotEmpty()) {
+                        this += carServicePackage
+                    }
                 }
             }
-        }
 
     private val SystemConfig.implicitToSourcePermissions: IndexedMap<String, IndexedListSet<String>>
         @Suppress("UNCHECKED_CAST")
-        get() = MutableIndexedMap<String, MutableIndexedListSet<String>>().apply {
-            splitPermissions.forEach { splitPermissionInfo ->
-                val sourcePermissionName = splitPermissionInfo.splitPermission
-                splitPermissionInfo.newPermissions.forEach { implicitPermissionName ->
-                    getOrPut(implicitPermissionName) { MutableIndexedListSet() } +=
-                        sourcePermissionName
+        get() =
+            MutableIndexedMap<String, MutableIndexedListSet<String>>().apply {
+                splitPermissions.forEach { splitPermissionInfo ->
+                    val sourcePermissionName = splitPermissionInfo.splitPermission
+                    splitPermissionInfo.newPermissions.forEach { implicitPermissionName ->
+                        getOrPut(implicitPermissionName) { MutableIndexedListSet() } +=
+                            sourcePermissionName
+                    }
                 }
-            }
-        } as IndexedMap<String, IndexedListSet<String>>
+            } as IndexedMap<String, IndexedListSet<String>>
 
     internal fun onUserAdded(userId: Int) {
-        mutateState {
-            with(policy) { onUserAdded(userId) }
-        }
+        mutateState { with(policy) { onUserAdded(userId) } }
     }
 
     internal fun onUserRemoved(userId: Int) {
-        mutateState {
-            with(policy) { onUserRemoved(userId) }
-        }
+        mutateState { with(policy) { onUserRemoved(userId) } }
     }
 
     internal fun onStorageVolumeMounted(
@@ -152,8 +156,12 @@
         mutateState {
             with(policy) {
                 onStorageVolumeMounted(
-                    packageStates, disabledSystemPackageStates, knownPackages, volumeUuid,
-                    packageNames, isSystemUpdated
+                    packageStates,
+                    disabledSystemPackageStates,
+                    knownPackages,
+                    volumeUuid,
+                    packageNames,
+                    isSystemUpdated
                 )
             }
         }
@@ -165,7 +173,10 @@
         mutateState {
             with(policy) {
                 onPackageAdded(
-                    packageStates, disabledSystemPackageStates, knownPackages, packageName
+                    packageStates,
+                    disabledSystemPackageStates,
+                    knownPackages,
+                    packageName
                 )
             }
         }
@@ -177,7 +188,11 @@
         mutateState {
             with(policy) {
                 onPackageRemoved(
-                    packageStates, disabledSystemPackageStates, knownPackages, packageName, appId
+                    packageStates,
+                    disabledSystemPackageStates,
+                    knownPackages,
+                    packageName,
+                    appId
                 )
             }
         }
@@ -189,7 +204,11 @@
         mutateState {
             with(policy) {
                 onPackageInstalled(
-                    packageStates, disabledSystemPackageStates, knownPackages, packageName, userId
+                    packageStates,
+                    disabledSystemPackageStates,
+                    knownPackages,
+                    packageName,
+                    userId
                 )
             }
         }
@@ -201,7 +220,11 @@
         mutateState {
             with(policy) {
                 onPackageUninstalled(
-                    packageStates, disabledSystemPackageStates, knownPackages, packageName, appId,
+                    packageStates,
+                    disabledSystemPackageStates,
+                    knownPackages,
+                    packageName,
+                    appId,
                     userId
                 )
             }
@@ -224,34 +247,42 @@
 
     private fun PackageManagerInternal.getKnownPackages(
         packageStates: Map<String, PackageState>
-    ): IntMap<Array<String>> = MutableIntMap<Array<String>>().apply {
-        this[KnownPackages.PACKAGE_INSTALLER] =
-            getKnownPackageNames(KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM)
-        this[KnownPackages.PACKAGE_PERMISSION_CONTROLLER] = getKnownPackageNames(
-            KnownPackages.PACKAGE_PERMISSION_CONTROLLER, UserHandle.USER_SYSTEM
-        )
-        this[KnownPackages.PACKAGE_VERIFIER] =
-            getKnownPackageNames(KnownPackages.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM)
-        this[KnownPackages.PACKAGE_SETUP_WIZARD] =
-            getKnownPackageNames(KnownPackages.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)
-        this[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER] = getKnownPackageNames(
-            KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER, UserHandle.USER_SYSTEM
-        )
-        this[KnownPackages.PACKAGE_CONFIGURATOR] =
-            getKnownPackageNames(KnownPackages.PACKAGE_CONFIGURATOR, UserHandle.USER_SYSTEM)
-        this[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER] = getKnownPackageNames(
-            KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER, UserHandle.USER_SYSTEM
-        )
-        this[KnownPackages.PACKAGE_APP_PREDICTOR] =
-            getKnownPackageNames(KnownPackages.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM)
-        this[KnownPackages.PACKAGE_COMPANION] =
-            getKnownPackageNames(KnownPackages.PACKAGE_COMPANION, UserHandle.USER_SYSTEM)
-        this[KnownPackages.PACKAGE_RETAIL_DEMO] =
-            getKnownPackageNames(KnownPackages.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM)
-                .filter { isProfileOwner(it, packageStates) }.toTypedArray()
-        this[KnownPackages.PACKAGE_RECENTS] =
-            getKnownPackageNames(KnownPackages.PACKAGE_RECENTS, UserHandle.USER_SYSTEM)
-    }
+    ): IntMap<Array<String>> =
+        MutableIntMap<Array<String>>().apply {
+            this[KnownPackages.PACKAGE_INSTALLER] =
+                getKnownPackageNames(KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM)
+            this[KnownPackages.PACKAGE_PERMISSION_CONTROLLER] =
+                getKnownPackageNames(
+                    KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
+                    UserHandle.USER_SYSTEM
+                )
+            this[KnownPackages.PACKAGE_VERIFIER] =
+                getKnownPackageNames(KnownPackages.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM)
+            this[KnownPackages.PACKAGE_SETUP_WIZARD] =
+                getKnownPackageNames(KnownPackages.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)
+            this[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER] =
+                getKnownPackageNames(
+                    KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER,
+                    UserHandle.USER_SYSTEM
+                )
+            this[KnownPackages.PACKAGE_CONFIGURATOR] =
+                getKnownPackageNames(KnownPackages.PACKAGE_CONFIGURATOR, UserHandle.USER_SYSTEM)
+            this[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER] =
+                getKnownPackageNames(
+                    KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER,
+                    UserHandle.USER_SYSTEM
+                )
+            this[KnownPackages.PACKAGE_APP_PREDICTOR] =
+                getKnownPackageNames(KnownPackages.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM)
+            this[KnownPackages.PACKAGE_COMPANION] =
+                getKnownPackageNames(KnownPackages.PACKAGE_COMPANION, UserHandle.USER_SYSTEM)
+            this[KnownPackages.PACKAGE_RETAIL_DEMO] =
+                getKnownPackageNames(KnownPackages.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM)
+                    .filter { isProfileOwner(it, packageStates) }
+                    .toTypedArray()
+            this[KnownPackages.PACKAGE_RECENTS] =
+                getKnownPackageNames(KnownPackages.PACKAGE_RECENTS, UserHandle.USER_SYSTEM)
+        }
 
     private fun isProfileOwner(
         packageName: String,
diff --git a/services/permission/java/com/android/server/permission/access/AccessPersistence.kt b/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
index a3f65af..d0913d2 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
@@ -38,16 +38,11 @@
 import java.io.File
 import java.io.FileNotFoundException
 
-class AccessPersistence(
-    private val policy: AccessPolicy
-) {
+class AccessPersistence(private val policy: AccessPolicy) {
     private val scheduleLock = Any()
-    @GuardedBy("scheduleLock")
-    private val pendingMutationTimesMillis = SparseLongArray()
-    @GuardedBy("scheduleLock")
-    private val pendingStates = MutableIntMap<AccessState>()
-    @GuardedBy("scheduleLock")
-    private lateinit var writeHandler: WriteHandler
+    @GuardedBy("scheduleLock") private val pendingMutationTimesMillis = SparseLongArray()
+    @GuardedBy("scheduleLock") private val pendingStates = MutableIntMap<AccessState>()
+    @GuardedBy("scheduleLock") private lateinit var writeHandler: WriteHandler
 
     private val writeLock = Any()
 
@@ -60,17 +55,16 @@
      */
     fun read(state: MutableAccessState) {
         readSystemState(state)
-        state.externalState.userIds.forEachIndexed { _, userId ->
-            readUserState(state, userId)
-        }
+        state.externalState.userIds.forEachIndexed { _, userId -> readUserState(state, userId) }
     }
 
     private fun readSystemState(state: MutableAccessState) {
-        val fileExists = systemFile.parse {
-            // This is the canonical way to call an extension function in a different class.
-            // TODO(b/259469752): Use context receiver for this when it becomes stable.
-            with(policy) { parseSystemState(state) }
-        }
+        val fileExists =
+            systemFile.parse {
+                // This is the canonical way to call an extension function in a different class.
+                // TODO(b/259469752): Use context receiver for this when it becomes stable.
+                with(policy) { parseSystemState(state) }
+            }
 
         if (!fileExists) {
             policy.migrateSystemState(state)
@@ -79,9 +73,8 @@
     }
 
     private fun readUserState(state: MutableAccessState, userId: Int) {
-        val fileExists = getUserFile(userId).parse {
-            with(policy) { parseUserState(state, userId) }
-        }
+        val fileExists =
+            getUserFile(userId).parse { with(policy) { parseUserState(state, userId) } }
 
         if (!fileExists) {
             policy.migrateUserState(state, userId)
@@ -90,8 +83,8 @@
     }
 
     /**
-     * @return {@code true} if the file is successfully read from the disk; {@code false} if
-     * the file doesn't exist yet.
+     * @return {@code true} if the file is successfully read from the disk; {@code false} if the
+     *   file doesn't exist yet.
      */
     private inline fun File.parse(block: BinaryXmlPullParser.() -> Unit): Boolean =
         try {
@@ -106,9 +99,7 @@
 
     fun write(state: AccessState) {
         state.systemState.write(state, UserHandle.USER_ALL)
-        state.userStates.forEachIndexed { _, userId, userState ->
-            userState.write(state, userId)
-        }
+        state.userStates.forEachIndexed { _, userId, userState -> userState.write(state, userId) }
     }
 
     private fun WritableState.write(state: AccessState, userId: Int) {
@@ -127,8 +118,10 @@
                     if (currentDelayMillis > MAX_WRITE_DELAY_MILLIS) {
                         message.sendToTarget()
                     } else {
-                        val newDelayMillis = WRITE_DELAY_TIME_MILLIS
-                            .coerceAtMost(MAX_WRITE_DELAY_MILLIS - currentDelayMillis)
+                        val newDelayMillis =
+                            WRITE_DELAY_TIME_MILLIS.coerceAtMost(
+                                MAX_WRITE_DELAY_MILLIS - currentDelayMillis
+                            )
                         writeHandler.sendMessageDelayed(message, newDelayMillis)
                     }
                 }
@@ -161,15 +154,11 @@
     }
 
     private fun writeSystemState(state: AccessState) {
-        systemFile.serialize {
-            with(policy) { serializeSystemState(state) }
-        }
+        systemFile.serialize { with(policy) { serializeSystemState(state) } }
     }
 
     private fun writeUserState(state: AccessState, userId: Int) {
-        getUserFile(userId).serialize {
-            with(policy) { serializeUserState(state, userId) }
-        }
+        getUserFile(userId).serialize { with(policy) { serializeUserState(state, userId) } }
     }
 
     private inline fun File.serialize(block: BinaryXmlSerializer.() -> Unit) {
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 6a349e2..754f77ec 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -37,21 +37,24 @@
 import com.android.server.pm.permission.PermissionAllowlist
 import com.android.server.pm.pkg.PackageState
 
-class AccessPolicy private constructor(
+class AccessPolicy
+private constructor(
     private val schemePolicies: IndexedMap<String, IndexedMap<String, SchemePolicy>>
 ) {
     @Suppress("UNCHECKED_CAST")
-    constructor() : this(
-        MutableIndexedMap<String, MutableIndexedMap<String, SchemePolicy>>().apply {
-            fun addPolicy(policy: SchemePolicy) {
-                getOrPut(policy.subjectScheme) { MutableIndexedMap() }[policy.objectScheme] = policy
-            }
-            addPolicy(AppIdPermissionPolicy())
-            addPolicy(DevicePermissionPolicy())
-            addPolicy(AppIdAppOpPolicy())
-            addPolicy(PackageAppOpPolicy())
-        } as IndexedMap<String, IndexedMap<String, SchemePolicy>>
-    )
+    constructor() :
+        this(
+            MutableIndexedMap<String, MutableIndexedMap<String, SchemePolicy>>().apply {
+                fun addPolicy(policy: SchemePolicy) {
+                    getOrPut(policy.subjectScheme) { MutableIndexedMap() }[policy.objectScheme] =
+                        policy
+                }
+                addPolicy(AppIdPermissionPolicy())
+                addPolicy(DevicePermissionPolicy())
+                addPolicy(AppIdAppOpPolicy())
+                addPolicy(PackageAppOpPolicy())
+            } as IndexedMap<String, IndexedMap<String, SchemePolicy>>
+        )
 
     fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy =
         checkNotNull(schemePolicies[subjectScheme]?.get(objectScheme)) {
@@ -92,23 +95,17 @@
     }
 
     fun GetStateScope.onStateMutated() {
-        forEachSchemePolicy {
-            with(it) { onStateMutated() }
-        }
+        forEachSchemePolicy { with(it) { onStateMutated() } }
     }
 
     fun MutateStateScope.onInitialized() {
-        forEachSchemePolicy {
-            with(it) { onInitialized() }
-        }
+        forEachSchemePolicy { with(it) { onInitialized() } }
     }
 
     fun MutateStateScope.onUserAdded(userId: Int) {
         newState.mutateExternalState().mutateUserIds() += userId
         newState.mutateUserStatesNoWrite()[userId] = MutableUserState()
-        forEachSchemePolicy {
-            with(it) { onUserAdded(userId) }
-        }
+        forEachSchemePolicy { with(it) { onUserAdded(userId) } }
         newState.externalState.packageStates.forEach { (_, packageState) ->
             upgradePackageVersion(packageState, userId)
         }
@@ -117,9 +114,7 @@
     fun MutateStateScope.onUserRemoved(userId: Int) {
         newState.mutateExternalState().mutateUserIds() -= userId
         newState.mutateUserStatesNoWrite() -= userId
-        forEachSchemePolicy {
-            with(it) { onUserRemoved(userId) }
-        }
+        forEachSchemePolicy { with(it) { onUserRemoved(userId) } }
     }
 
     fun MutateStateScope.onStorageVolumeMounted(
@@ -154,9 +149,7 @@
             setKnownPackages(knownPackages)
         }
         addedAppIds.forEachIndexed { _, appId ->
-            forEachSchemePolicy {
-                with(it) { onAppIdAdded(appId) }
-            }
+            forEachSchemePolicy { with(it) { onAppIdAdded(appId) } }
         }
         forEachSchemePolicy {
             with(it) { onStorageVolumeMounted(volumeUuid, packageNames, isSystemUpdated) }
@@ -192,13 +185,9 @@
             setKnownPackages(knownPackages)
         }
         if (isAppIdAdded) {
-            forEachSchemePolicy {
-                with(it) { onAppIdAdded(appId) }
-            }
+            forEachSchemePolicy { with(it) { onAppIdAdded(appId) } }
         }
-        forEachSchemePolicy {
-            with(it) { onPackageAdded(packageState) }
-        }
+        forEachSchemePolicy { with(it) { onPackageAdded(packageState) } }
         newState.userStates.forEachIndexed { _, userId, _ ->
             upgradePackageVersion(packageState, userId)
         }
@@ -227,13 +216,9 @@
             }
             setKnownPackages(knownPackages)
         }
-        forEachSchemePolicy {
-            with(it) { onPackageRemoved(packageName, appId) }
-        }
+        forEachSchemePolicy { with(it) { onPackageRemoved(packageName, appId) } }
         if (isAppIdRemoved) {
-            forEachSchemePolicy {
-                with(it) { onAppIdRemoved(appId) }
-            }
+            forEachSchemePolicy { with(it) { onAppIdRemoved(appId) } }
         }
         newState.userStates.forEachIndexed { userStateIndex, _, userState ->
             if (packageName in userState.packageVersions) {
@@ -258,9 +243,7 @@
         checkNotNull(packageState) {
             "Installed package $packageName isn't found in packageStates in onPackageInstalled()"
         }
-        forEachSchemePolicy {
-            with(it) { onPackageInstalled(packageState, userId) }
-        }
+        forEachSchemePolicy { with(it) { onPackageInstalled(packageState, userId) } }
     }
 
     fun MutateStateScope.onPackageUninstalled(
@@ -276,9 +259,7 @@
             setDisabledSystemPackageStates(disabledSystemPackageStates)
             setKnownPackages(knownPackages)
         }
-        forEachSchemePolicy {
-            with(it) { onPackageUninstalled(packageName, appId, userId) }
-        }
+        forEachSchemePolicy { with(it) { onPackageUninstalled(packageName, appId, userId) } }
     }
 
     fun MutateStateScope.onSystemReady(
@@ -292,21 +273,15 @@
             setKnownPackages(knownPackages)
             setSystemReady(true)
         }
-        forEachSchemePolicy {
-            with(it) { onSystemReady() }
-        }
+        forEachSchemePolicy { with(it) { onSystemReady() } }
     }
 
     fun migrateSystemState(state: MutableAccessState) {
-        forEachSchemePolicy {
-            with(it) { migrateSystemState(state) }
-        }
+        forEachSchemePolicy { with(it) { migrateSystemState(state) } }
     }
 
     fun migrateUserState(state: MutableAccessState, userId: Int) {
-        forEachSchemePolicy {
-            with(it) { migrateUserState(state, userId) }
-        }
+        forEachSchemePolicy { with(it) { migrateUserState(state, userId) } }
     }
 
     private fun MutateStateScope.upgradePackageVersion(packageState: PackageState, userId: Int) {
@@ -330,10 +305,12 @@
                     VERSION_LATEST
             }
             version == VERSION_LATEST -> {}
-            else -> Slog.w(
-                LOG_TAG, "Unexpected version $version for package $packageName," +
-                    "latest version is $VERSION_LATEST"
-            )
+            else ->
+                Slog.w(
+                    LOG_TAG,
+                    "Unexpected version $version for package $packageName," +
+                        "latest version is $VERSION_LATEST"
+                )
         }
     }
 
@@ -341,11 +318,7 @@
         forEachTag {
             when (tagName) {
                 TAG_ACCESS -> {
-                    forEachTag {
-                        forEachSchemePolicy {
-                            with(it) { parseSystemState(state) }
-                        }
-                    }
+                    forEachTag { forEachSchemePolicy { with(it) { parseSystemState(state) } } }
                 }
                 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $tagName when parsing system state")
             }
@@ -353,11 +326,7 @@
     }
 
     fun BinaryXmlSerializer.serializeSystemState(state: AccessState) {
-        tag(TAG_ACCESS) {
-            forEachSchemePolicy {
-                with(it) { serializeSystemState(state) }
-            }
-        }
+        tag(TAG_ACCESS) { forEachSchemePolicy { with(it) { serializeSystemState(state) } } }
     }
 
     fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
@@ -370,9 +339,7 @@
                             TAG_DEFAULT_PERMISSION_GRANT ->
                                 parseDefaultPermissionGrant(state, userId)
                             else -> {
-                                forEachSchemePolicy {
-                                    with(it) { parseUserState(state, userId) }
-                                }
+                                forEachSchemePolicy { with(it) { parseUserState(state, userId) } }
                             }
                         }
                     }
@@ -428,9 +395,7 @@
             serializeDefaultPermissionGrantFingerprint(
                 state.userStates[userId]!!.defaultPermissionGrantFingerprint
             )
-            forEachSchemePolicy {
-                with(it) { serializeUserState(state, userId) }
-            }
+            forEachSchemePolicy { with(it) { serializeUserState(state, userId) } }
         }
     }
 
@@ -451,9 +416,7 @@
         fingerprint: String?
     ) {
         if (fingerprint != null) {
-            tag(TAG_DEFAULT_PERMISSION_GRANT) {
-                attributeInterned(ATTR_FINGERPRINT, fingerprint)
-            }
+            tag(TAG_DEFAULT_PERMISSION_GRANT) { attributeInterned(ATTR_FINGERPRINT, fingerprint) }
         }
     }
 
@@ -462,9 +425,7 @@
 
     private inline fun forEachSchemePolicy(action: (SchemePolicy) -> Unit) {
         schemePolicies.forEachIndexed { _, _, objectSchemePolicies ->
-            objectSchemePolicies.forEachIndexed { _, _, schemePolicy ->
-                action(schemePolicy)
-            }
+            objectSchemePolicies.forEachIndexed { _, _, schemePolicy -> action(schemePolicy) }
         }
     }
 
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index 94c878a..49d2f81 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -28,7 +28,9 @@
 private typealias SystemStateReference = MutableReference<SystemState, MutableSystemState>
 
 typealias UserStates = IntReferenceMap<UserState, MutableUserState>
+
 typealias MutableUserStates = MutableIntReferenceMap<UserState, MutableUserState>
+
 private typealias UserStatesReference = MutableReference<UserStates, MutableUserStates>
 
 sealed class AccessState(
@@ -48,22 +50,22 @@
     override fun toMutable(): MutableAccessState = MutableAccessState(this)
 }
 
-class MutableAccessState private constructor(
+class MutableAccessState
+private constructor(
     externalStateReference: ExternalStateReference,
     systemStateReference: SystemStateReference,
     userStatesReference: UserStatesReference
-) : AccessState(
-    externalStateReference,
-    systemStateReference,
-    userStatesReference
-) {
-    constructor() : this(
-        ExternalStateReference(MutableExternalState()),
-        SystemStateReference(MutableSystemState()),
-        UserStatesReference(MutableUserStates())
-    )
+) : AccessState(externalStateReference, systemStateReference, userStatesReference) {
+    constructor() :
+        this(
+            ExternalStateReference(MutableExternalState()),
+            SystemStateReference(MutableSystemState()),
+            UserStatesReference(MutableUserStates())
+        )
 
-    internal constructor(accessState: AccessState) : this(
+    internal constructor(
+        accessState: AccessState
+    ) : this(
         accessState.externalStateReference.toImmutable(),
         accessState.systemStateReference.toImmutable(),
         accessState.userStatesReference.toImmutable()
@@ -86,8 +88,10 @@
 private typealias UserIdsReference = MutableReference<IntSet, MutableIntSet>
 
 typealias AppIdPackageNames = IntReferenceMap<IndexedListSet<String>, MutableIndexedListSet<String>>
+
 typealias MutableAppIdPackageNames =
     MutableIntReferenceMap<IndexedListSet<String>, MutableIndexedListSet<String>>
+
 private typealias AppIdPackageNamesReference =
     MutableReference<AppIdPackageNames, MutableAppIdPackageNames>
 
@@ -142,7 +146,8 @@
     override fun toMutable(): MutableExternalState = MutableExternalState(this)
 }
 
-class MutableExternalState private constructor(
+class MutableExternalState
+private constructor(
     userIdsReference: UserIdsReference,
     packageStates: Map<String, PackageState>,
     disabledSystemPackageStates: Map<String, PackageState>,
@@ -154,34 +159,38 @@
     permissionAllowlist: PermissionAllowlist,
     implicitToSourcePermissions: IndexedMap<String, IndexedListSet<String>>,
     isSystemReady: Boolean
-) : ExternalState(
-    userIdsReference,
-    packageStates,
-    disabledSystemPackageStates,
-    appIdPackageNamesReference,
-    knownPackages,
-    isLeanback,
-    configPermissions,
-    privilegedPermissionAllowlistPackages,
-    permissionAllowlist,
-    implicitToSourcePermissions,
-    isSystemReady
-) {
-    constructor() : this(
-        UserIdsReference(MutableIntSet()),
-        emptyMap(),
-        emptyMap(),
-        AppIdPackageNamesReference(MutableAppIdPackageNames()),
-        MutableIntMap(),
-        false,
-        emptyMap(),
-        MutableIndexedListSet(),
-        PermissionAllowlist(),
-        MutableIndexedMap(),
-        false
-    )
+) :
+    ExternalState(
+        userIdsReference,
+        packageStates,
+        disabledSystemPackageStates,
+        appIdPackageNamesReference,
+        knownPackages,
+        isLeanback,
+        configPermissions,
+        privilegedPermissionAllowlistPackages,
+        permissionAllowlist,
+        implicitToSourcePermissions,
+        isSystemReady
+    ) {
+    constructor() :
+        this(
+            UserIdsReference(MutableIntSet()),
+            emptyMap(),
+            emptyMap(),
+            AppIdPackageNamesReference(MutableAppIdPackageNames()),
+            MutableIntMap(),
+            false,
+            emptyMap(),
+            MutableIndexedListSet(),
+            PermissionAllowlist(),
+            MutableIndexedMap(),
+            false
+        )
 
-    internal constructor(externalState: ExternalState) : this(
+    internal constructor(
+        externalState: ExternalState
+    ) : this(
         externalState.userIdsReference.toImmutable(),
         externalState.packageStates,
         externalState.disabledSystemPackageStates,
@@ -249,9 +258,10 @@
     }
 }
 
-private typealias PermissionGroupsReference = MutableReference<
-    IndexedMap<String, PermissionGroupInfo>, MutableIndexedMap<String, PermissionGroupInfo>
->
+private typealias PermissionGroupsReference =
+    MutableReference<
+        IndexedMap<String, PermissionGroupInfo>, MutableIndexedMap<String, PermissionGroupInfo>
+    >
 
 private typealias PermissionTreesReference =
     MutableReference<IndexedMap<String, Permission>, MutableIndexedMap<String, Permission>>
@@ -280,25 +290,31 @@
     override fun toMutable(): MutableSystemState = MutableSystemState(this)
 }
 
-class MutableSystemState private constructor(
+class MutableSystemState
+private constructor(
     permissionGroupsReference: PermissionGroupsReference,
     permissionTreesReference: PermissionTreesReference,
     permissionsReference: PermissionsReference,
     writeMode: Int
-) : SystemState(
-    permissionGroupsReference,
-    permissionTreesReference,
-    permissionsReference,
-    writeMode
-), MutableWritableState {
-    constructor() : this(
-        PermissionGroupsReference(MutableIndexedMap()),
-        PermissionTreesReference(MutableIndexedMap()),
-        PermissionsReference(MutableIndexedMap()),
-        WriteMode.NONE
-    )
+) :
+    SystemState(
+        permissionGroupsReference,
+        permissionTreesReference,
+        permissionsReference,
+        writeMode
+    ),
+    MutableWritableState {
+    constructor() :
+        this(
+            PermissionGroupsReference(MutableIndexedMap()),
+            PermissionTreesReference(MutableIndexedMap()),
+            PermissionsReference(MutableIndexedMap()),
+            WriteMode.NONE
+        )
 
-    internal constructor(systemState: SystemState) : this(
+    internal constructor(
+        systemState: SystemState
+    ) : this(
         systemState.permissionGroupsReference.toImmutable(),
         systemState.permissionTreesReference.toImmutable(),
         systemState.permissionsReference.toImmutable(),
@@ -311,8 +327,7 @@
     fun mutatePermissionTrees(): MutableIndexedMap<String, Permission> =
         permissionTreesReference.mutate()
 
-    fun mutatePermissions(): MutableIndexedMap<String, Permission> =
-        permissionsReference.mutate()
+    fun mutatePermissions(): MutableIndexedMap<String, Permission> = permissionsReference.mutate()
 
     override fun requestWriteMode(writeMode: Int) {
         this.writeMode = maxOf(this.writeMode, writeMode)
@@ -324,34 +339,42 @@
 
 typealias AppIdPermissionFlags =
     IntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+
 typealias MutableAppIdPermissionFlags =
     MutableIntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+
 private typealias AppIdPermissionFlagsReference =
     MutableReference<AppIdPermissionFlags, MutableAppIdPermissionFlags>
 
-
 typealias DevicePermissionFlags =
     IndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+
 typealias MutableDevicePermissionFlags =
     MutableIndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+
 typealias AppIdDevicePermissionFlags =
     IntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
+
 typealias MutableAppIdDevicePermissionFlags =
     MutableIntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
+
 private typealias AppIdDevicePermissionFlagsReference =
     MutableReference<AppIdDevicePermissionFlags, MutableAppIdDevicePermissionFlags>
 
-typealias AppIdAppOpModes =
-    IntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+typealias AppIdAppOpModes = IntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+
 typealias MutableAppIdAppOpModes =
     MutableIntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+
 private typealias AppIdAppOpModesReference =
     MutableReference<AppIdAppOpModes, MutableAppIdAppOpModes>
 
 typealias PackageAppOpModes =
     IndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+
 typealias MutablePackageAppOpModes =
     MutableIndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+
 private typealias PackageAppOpModesReference =
     MutableReference<PackageAppOpModes, MutablePackageAppOpModes>
 
@@ -388,7 +411,8 @@
     override fun toMutable(): MutableUserState = MutableUserState(this)
 }
 
-class MutableUserState private constructor(
+class MutableUserState
+private constructor(
     packageVersionsReference: PackageVersionsReference,
     appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
     appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
@@ -396,26 +420,31 @@
     packageAppOpModesReference: PackageAppOpModesReference,
     defaultPermissionGrantFingerprint: String?,
     writeMode: Int
-) : UserState(
-    packageVersionsReference,
-    appIdPermissionFlagsReference,
-    appIdDevicePermissionFlagsReference,
-    appIdAppOpModesReference,
-    packageAppOpModesReference,
-    defaultPermissionGrantFingerprint,
-    writeMode
-), MutableWritableState {
-    constructor() : this(
-        PackageVersionsReference(MutableIndexedMap<String, Int>()),
-        AppIdPermissionFlagsReference(MutableAppIdPermissionFlags()),
-        AppIdDevicePermissionFlagsReference(MutableAppIdDevicePermissionFlags()),
-        AppIdAppOpModesReference(MutableAppIdAppOpModes()),
-        PackageAppOpModesReference(MutablePackageAppOpModes()),
-        null,
-        WriteMode.NONE
-    )
+) :
+    UserState(
+        packageVersionsReference,
+        appIdPermissionFlagsReference,
+        appIdDevicePermissionFlagsReference,
+        appIdAppOpModesReference,
+        packageAppOpModesReference,
+        defaultPermissionGrantFingerprint,
+        writeMode
+    ),
+    MutableWritableState {
+    constructor() :
+        this(
+            PackageVersionsReference(MutableIndexedMap<String, Int>()),
+            AppIdPermissionFlagsReference(MutableAppIdPermissionFlags()),
+            AppIdDevicePermissionFlagsReference(MutableAppIdDevicePermissionFlags()),
+            AppIdAppOpModesReference(MutableAppIdAppOpModes()),
+            PackageAppOpModesReference(MutablePackageAppOpModes()),
+            null,
+            WriteMode.NONE
+        )
 
-    internal constructor(userState: UserState) : this(
+    internal constructor(
+        userState: UserState
+    ) : this(
         userState.packageVersionsReference.toImmutable(),
         userState.appIdPermissionFlagsReference.toImmutable(),
         userState.appIdDevicePermissionFlagsReference.toImmutable(),
@@ -461,11 +490,7 @@
     fun requestWriteMode(writeMode: Int)
 }
 
-open class GetStateScope(
-    val state: AccessState
-)
+open class GetStateScope(val state: AccessState)
 
-class MutateStateScope(
-    val oldState: AccessState,
-    val newState: MutableAccessState
-) : GetStateScope(newState)
+class MutateStateScope(val oldState: AccessState, val newState: MutableAccessState) :
+    GetStateScope(newState)
diff --git a/services/permission/java/com/android/server/permission/access/AccessUri.kt b/services/permission/java/com/android/server/permission/access/AccessUri.kt
index 1d46ca7..1f5a4df 100644
--- a/services/permission/java/com/android/server/permission/access/AccessUri.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessUri.kt
@@ -18,9 +18,7 @@
 
 import android.os.UserHandle
 
-sealed class AccessUri(
-    val scheme: String
-) {
+sealed class AccessUri(val scheme: String) {
     override fun equals(other: Any?): Boolean {
         throw NotImplementedError()
     }
@@ -34,9 +32,7 @@
     }
 }
 
-data class AppOpUri(
-    val appOpName: String
-) : AccessUri(SCHEME) {
+data class AppOpUri(val appOpName: String) : AccessUri(SCHEME) {
     override fun toString(): String = "$scheme:///$appOpName"
 
     companion object {
@@ -44,10 +40,7 @@
     }
 }
 
-data class PackageUri(
-    val packageName: String,
-    val userId: Int
-) : AccessUri(SCHEME) {
+data class PackageUri(val packageName: String, val userId: Int) : AccessUri(SCHEME) {
     override fun toString(): String = "$scheme:///$packageName/$userId"
 
     companion object {
@@ -55,9 +48,7 @@
     }
 }
 
-data class PermissionUri(
-    val permissionName: String
-) : AccessUri(SCHEME) {
+data class PermissionUri(val permissionName: String) : AccessUri(SCHEME) {
     override fun toString(): String = "$scheme:///$permissionName"
 
     companion object {
@@ -65,10 +56,7 @@
     }
 }
 
-data class DevicePermissionUri(
-    val permissionName: String,
-    val deviceId: Int
-) : AccessUri(SCHEME) {
+data class DevicePermissionUri(val permissionName: String, val deviceId: Int) : AccessUri(SCHEME) {
     override fun toString(): String = "$scheme:///$permissionName/$deviceId"
 
     companion object {
@@ -76,9 +64,7 @@
     }
 }
 
-data class UidUri(
-    val uid: Int
-) : AccessUri(SCHEME) {
+data class UidUri(val uid: Int) : AccessUri(SCHEME) {
     val userId: Int
         get() = UserHandle.getUserId(uid)
 
diff --git a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpMigration.kt b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpMigration.kt
index 96d315e..6c1b080 100644
--- a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpMigration.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpMigration.kt
@@ -46,9 +46,7 @@
 
             val appOpModes = MutableIndexedMap<String, Int>()
             appIdAppOpModes[appId] = appOpModes
-            legacyAppOpModes.forEach { (appOpName, appOpMode) ->
-                appOpModes[appOpName] = appOpMode
-            }
+            legacyAppOpModes.forEach { (appOpName, appOpMode) -> appOpModes[appOpName] = appOpMode }
 
             if (packageNames != null) {
                 val packageVersions = userState.mutatePackageVersions()
diff --git a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPersistence.kt b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPersistence.kt
index 4c7e946..f291b1a 100644
--- a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPersistence.kt
@@ -51,8 +51,10 @@
         }
         userState.appIdAppOpModes.forEachReversedIndexed { appIdIndex, appId, _ ->
             // Non-application UIDs may not have an Android package but may still have app op state.
-            if (appId !in state.externalState.appIdPackageNames &&
-                appId >= Process.FIRST_APPLICATION_UID) {
+            if (
+                appId !in state.externalState.appIdPackageNames &&
+                    appId >= Process.FIRST_APPLICATION_UID
+            ) {
                 Slog.w(LOG_TAG, "Dropping unknown app ID $appId when parsing app-op state")
                 appIdAppOpModes.removeAt(appIdIndex)
                 userState.requestWriteMode(WriteMode.ASYNCHRONOUS)
diff --git a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
index c02fe4d..94caf28 100644
--- a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
@@ -46,7 +46,9 @@
         newState.userStates.forEachIndexed { userStateIndex, _, userState ->
             val appIdIndex = userState.appIdAppOpModes.indexOfKey(appId)
             if (appIdIndex >= 0) {
-                newState.mutateUserStateAt(userStateIndex).mutateAppIdAppOpModes()
+                newState
+                    .mutateUserStateAt(userStateIndex)
+                    .mutateAppIdAppOpModes()
                     .removeAt(appIdIndex)
                 // Skip notifying the change listeners since the app ID no longer exists.
             }
@@ -61,8 +63,8 @@
         if (userStateIndex < 0) {
             return false
         }
-        val appIdIndex = newState.userStates.valueAt(userStateIndex).appIdAppOpModes
-            .indexOfKey(appId)
+        val appIdIndex =
+            newState.userStates.valueAt(userStateIndex).appIdAppOpModes.indexOfKey(appId)
         if (appIdIndex < 0) {
             return false
         }
@@ -71,7 +73,9 @@
     }
 
     fun GetStateScope.getAppOpMode(appId: Int, userId: Int, appOpName: String): Int =
-        state.userStates[userId]?.appIdAppOpModes?.get(appId)
+        state.userStates[userId]
+            ?.appIdAppOpModes
+            ?.get(appId)
             .getWithDefault(appOpName, AppOpsManager.opToDefaultMode(appOpName))
 
     fun MutateStateScope.setAppOpMode(
@@ -81,8 +85,10 @@
         mode: Int
     ): Boolean {
         val defaultMode = AppOpsManager.opToDefaultMode(appOpName)
-        val oldMode = newState.userStates[userId]!!.appIdAppOpModes[appId]
-            .getWithDefault(appOpName, defaultMode)
+        val oldMode =
+            newState.userStates[userId]!!
+                .appIdAppOpModes[appId]
+                .getWithDefault(appOpName, defaultMode)
         if (oldMode == mode) {
             return false
         }
@@ -122,9 +128,7 @@
         with(upgrade) { upgradePackageState(packageState, userId, version) }
     }
 
-    /**
-     * Listener for app op mode changes.
-     */
+    /** Listener for app op mode changes. */
     abstract class OnAppOpModeChangedListener {
         /**
          * Called when an app op mode change has been made to the upcoming new state.
diff --git a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpUpgrade.kt b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpUpgrade.kt
index 12df95e..10c7764 100644
--- a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpUpgrade.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpUpgrade.kt
@@ -28,11 +28,13 @@
     ) {
         if (version <= 2) {
             with(policy) {
-                val appOpMode = getAppOpMode(
-                    packageState.appId, userId, AppOpsManager.OPSTR_RUN_IN_BACKGROUND
-                )
+                val appOpMode =
+                    getAppOpMode(packageState.appId, userId, AppOpsManager.OPSTR_RUN_IN_BACKGROUND)
                 setAppOpMode(
-                    packageState.appId, userId, AppOpsManager.OPSTR_RUN_ANY_IN_BACKGROUND, appOpMode
+                    packageState.appId,
+                    userId,
+                    AppOpsManager.OPSTR_RUN_ANY_IN_BACKGROUND,
+                    appOpMode
                 )
             }
         }
@@ -40,14 +42,19 @@
             val permissionName = AppOpsManager.opToPermission(AppOpsManager.OP_SCHEDULE_EXACT_ALARM)
             if (permissionName in packageState.androidPackage!!.requestedPermissions) {
                 with(policy) {
-                    val appOpMode = getAppOpMode(
-                        packageState.appId, userId, AppOpsManager.OPSTR_SCHEDULE_EXACT_ALARM
-                    )
+                    val appOpMode =
+                        getAppOpMode(
+                            packageState.appId,
+                            userId,
+                            AppOpsManager.OPSTR_SCHEDULE_EXACT_ALARM
+                        )
                     val defaultAppOpMode =
                         AppOpsManager.opToDefaultMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM)
                     if (appOpMode == defaultAppOpMode) {
                         setAppOpMode(
-                            packageState.appId, userId, AppOpsManager.OPSTR_SCHEDULE_EXACT_ALARM,
+                            packageState.appId,
+                            userId,
+                            AppOpsManager.OPSTR_SCHEDULE_EXACT_ALARM,
                             AppOpsManager.MODE_ALLOWED
                         )
                     }
diff --git a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt
index 5b91ad9..26ea9d2 100644
--- a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt
@@ -33,19 +33,16 @@
 import com.android.server.permission.access.collection.forEachIndexed
 import com.android.server.permission.access.collection.set
 
-class AppOpService(
-    private val service: AccessCheckingService
-) : AppOpsCheckingServiceInterface {
-    private val packagePolicy = service.getSchemePolicy(PackageUri.SCHEME, AppOpUri.SCHEME)
-        as PackageAppOpPolicy
-    private val appIdPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME)
-        as AppIdAppOpPolicy
+class AppOpService(private val service: AccessCheckingService) : AppOpsCheckingServiceInterface {
+    private val packagePolicy =
+        service.getSchemePolicy(PackageUri.SCHEME, AppOpUri.SCHEME) as PackageAppOpPolicy
+    private val appIdPolicy =
+        service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as AppIdAppOpPolicy
 
     private val context = service.context
     private lateinit var handler: Handler
 
-    @Volatile
-    private var listeners = ArraySet<AppOpsModeChangedListener>()
+    @Volatile private var listeners = ArraySet<AppOpsModeChangedListener>()
     private val listenersLock = Any()
 
     fun initialize() {
@@ -86,9 +83,7 @@
         val appId = UserHandle.getAppId(uid)
         val userId = UserHandle.getUserId(uid)
         val opName = AppOpsManager.opToPublicName(op)
-        return service.getState {
-            with(appIdPolicy) { getAppOpMode(appId, userId, opName) }
-        }
+        return service.getState { with(appIdPolicy) { getAppOpMode(appId, userId, opName) } }
     }
 
     private fun getUidModes(uid: Int): ArrayMap<String, Int>? {
@@ -115,10 +110,7 @@
         }
     }
 
-    private fun getPackageModes(
-        packageName: String,
-        userId: Int
-    ): ArrayMap<String, Int>? =
+    private fun getPackageModes(packageName: String, userId: Int): ArrayMap<String, Int>? =
         service.getState { with(packagePolicy) { getAppOpModes(packageName, userId) } }?.map
 
     override fun setPackageMode(packageName: String, op: Int, mode: Int, userId: Int) {
@@ -131,15 +123,13 @@
     override fun removeUid(uid: Int) {
         val appId = UserHandle.getAppId(uid)
         val userId = UserHandle.getUserId(uid)
-        service.mutateState {
-            with(appIdPolicy) { removeAppOpModes(appId, userId) }
-        }
+        service.mutateState { with(appIdPolicy) { removeAppOpModes(appId, userId) } }
     }
 
     override fun removePackage(packageName: String, userId: Int): Boolean {
         var wasChanged = false
         service.mutateState {
-            wasChanged = with (packagePolicy) { removeAppOpModes(packageName, userId) }
+            wasChanged = with(packagePolicy) { removeAppOpModes(packageName, userId) }
         }
         return wasChanged
     }
diff --git a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPersistence.kt b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPersistence.kt
index a267637..edeef71 100644
--- a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPersistence.kt
@@ -52,9 +52,7 @@
     }
 
     protected fun BinaryXmlSerializer.serializeAppOps(appOpModes: IndexedMap<String, Int>) {
-        appOpModes.forEachIndexed { _, name, mode ->
-            serializeAppOp(name, mode)
-        }
+        appOpModes.forEachIndexed { _, name, mode -> serializeAppOp(name, mode) }
     }
 
     private fun BinaryXmlSerializer.serializeAppOp(name: String, mode: Int) {
diff --git a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
index c0a85f8..758cec0 100644
--- a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
@@ -23,9 +23,7 @@
 import com.android.server.permission.access.MutableAccessState
 import com.android.server.permission.access.SchemePolicy
 
-abstract class BaseAppOpPolicy(
-    private val persistence: BaseAppOpPersistence
-) : SchemePolicy() {
+abstract class BaseAppOpPolicy(private val persistence: BaseAppOpPersistence) : SchemePolicy() {
     override val objectScheme: String
         get() = AppOpUri.SCHEME
 
diff --git a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpMigration.kt b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpMigration.kt
index 03311a2..8797e39 100644
--- a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpMigration.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpMigration.kt
@@ -44,9 +44,7 @@
 
             val appOpModes = MutableIndexedMap<String, Int>()
             packageAppOpModes[packageName] = appOpModes
-            legacyAppOpModes.forEach { (appOpName, appOpMode) ->
-                appOpModes[appOpName] = appOpMode
-            }
+            legacyAppOpModes.forEach { (appOpName, appOpMode) -> appOpModes[appOpName] = appOpMode }
 
             userState.mutatePackageVersions()[packageName] = version
         }
diff --git a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
index 5398a57..0d9470e 100644
--- a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
@@ -46,7 +46,9 @@
         newState.userStates.forEachIndexed { userStateIndex, _, userState ->
             val packageNameIndex = userState.packageAppOpModes.indexOfKey(packageName)
             if (packageNameIndex >= 0) {
-                newState.mutateUserStateAt(userStateIndex).mutatePackageAppOpModes()
+                newState
+                    .mutateUserStateAt(userStateIndex)
+                    .mutatePackageAppOpModes()
                     .removeAt(packageNameIndex)
                 // Skip notifying the change listeners since the package no longer exists.
             }
@@ -61,18 +63,22 @@
         if (userStateIndex < 0) {
             return false
         }
-        val packageNameIndex = newState.userStates.valueAt(userStateIndex).packageAppOpModes
-            .indexOfKey(packageName)
+        val packageNameIndex =
+            newState.userStates.valueAt(userStateIndex).packageAppOpModes.indexOfKey(packageName)
         if (packageNameIndex < 0) {
             return false
         }
-        newState.mutateUserStateAt(userStateIndex).mutatePackageAppOpModes()
+        newState
+            .mutateUserStateAt(userStateIndex)
+            .mutatePackageAppOpModes()
             .removeAt(packageNameIndex)
         return true
     }
 
     fun GetStateScope.getAppOpMode(packageName: String, userId: Int, appOpName: String): Int =
-        state.userStates[userId]?.packageAppOpModes?.get(packageName)
+        state.userStates[userId]
+            ?.packageAppOpModes
+            ?.get(packageName)
             .getWithDefault(appOpName, AppOpsManager.opToDefaultMode(appOpName))
 
     fun MutateStateScope.setAppOpMode(
@@ -82,8 +88,10 @@
         mode: Int
     ): Boolean {
         val defaultMode = AppOpsManager.opToDefaultMode(appOpName)
-        val oldMode = newState.userStates[userId]!!.packageAppOpModes[packageName]
-            .getWithDefault(appOpName, defaultMode)
+        val oldMode =
+            newState.userStates[userId]!!
+                .packageAppOpModes[packageName]
+                .getWithDefault(appOpName, defaultMode)
         if (oldMode == mode) {
             return false
         }
@@ -123,9 +131,7 @@
         with(upgrade) { upgradePackageState(packageState, userId, version) }
     }
 
-    /**
-     * Listener for app op mode changes.
-     */
+    /** Listener for app op mode changes. */
     abstract class OnAppOpModeChangedListener {
         /**
          * Called when an app op mode change has been made to the upcoming new state.
diff --git a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpUpgrade.kt b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpUpgrade.kt
index 8e37093..f5eedf7 100644
--- a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpUpgrade.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpUpgrade.kt
@@ -28,11 +28,16 @@
     ) {
         if (version <= 2) {
             with(policy) {
-                val appOpMode = getAppOpMode(
-                    packageState.packageName, userId, AppOpsManager.OPSTR_RUN_IN_BACKGROUND
-                )
+                val appOpMode =
+                    getAppOpMode(
+                        packageState.packageName,
+                        userId,
+                        AppOpsManager.OPSTR_RUN_IN_BACKGROUND
+                    )
                 setAppOpMode(
-                    packageState.packageName, userId, AppOpsManager.OPSTR_RUN_ANY_IN_BACKGROUND,
+                    packageState.packageName,
+                    userId,
+                    AppOpsManager.OPSTR_RUN_ANY_IN_BACKGROUND,
                     appOpMode
                 )
             }
diff --git a/services/permission/java/com/android/server/permission/access/collection/ArrayMapExtensions.kt b/services/permission/java/com/android/server/permission/access/collection/ArrayMapExtensions.kt
index 686db42..b74f477 100644
--- a/services/permission/java/com/android/server/permission/access/collection/ArrayMapExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/ArrayMapExtensions.kt
@@ -49,7 +49,9 @@
 }
 
 inline fun <K, V> ArrayMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
-    get(key)?.let { return it }
+    get(key)?.let {
+        return it
+    }
     return defaultValue().also { put(key, it) }
 }
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedList.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedList.kt
index ce4aa44..ea8e07f 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedList.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedList.kt
@@ -16,12 +16,8 @@
 
 package com.android.server.permission.access.immutable
 
-/**
- * Immutable list with index-based access.
- */
-sealed class IndexedList<T>(
-    internal val list: ArrayList<T>
-) : Immutable<MutableIndexedList<T>> {
+/** Immutable list with index-based access. */
+sealed class IndexedList<T>(internal val list: ArrayList<T>) : Immutable<MutableIndexedList<T>> {
     val size: Int
         get() = list.size
 
@@ -29,20 +25,15 @@
 
     operator fun contains(element: T): Boolean = list.contains(element)
 
-    @Suppress("ReplaceGetOrSet")
-    operator fun get(index: Int): T = list.get(index)
+    @Suppress("ReplaceGetOrSet") operator fun get(index: Int): T = list.get(index)
 
     override fun toMutable(): MutableIndexedList<T> = MutableIndexedList(this)
 
     override fun toString(): String = list.toString()
 }
 
-/**
- * Mutable list with index-based access.
- */
-class MutableIndexedList<T>(
-    list: ArrayList<T> = ArrayList()
-) : IndexedList<T>(list) {
+/** Mutable list with index-based access. */
+class MutableIndexedList<T>(list: ArrayList<T> = ArrayList()) : IndexedList<T>(list) {
     constructor(indexedList: IndexedList<T>) : this(ArrayList(indexedList.list))
 
     @Suppress("ReplaceGetOrSet")
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedListExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedListExtensions.kt
index dc9bae3..a9d804e 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedListExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedListExtensions.kt
@@ -70,9 +70,7 @@
     accumulator: (Int, Int, T) -> Int
 ): Int {
     var value = initialValue
-    forEachIndexed { index, element ->
-        value = accumulator(value, index, element)
-    }
+    forEachIndexed { index, element -> value = accumulator(value, index, element) }
     return value
 }
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedListSet.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedListSet.kt
index 77e71ba..3a2fd2f 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedListSet.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedListSet.kt
@@ -16,12 +16,9 @@
 
 package com.android.server.permission.access.immutable
 
-/**
- * Immutable set with index-based access, implemented using a list.
- */
-sealed class IndexedListSet<T>(
-    internal val list: ArrayList<T>
-) : Immutable<MutableIndexedListSet<T>> {
+/** Immutable set with index-based access, implemented using a list. */
+sealed class IndexedListSet<T>(internal val list: ArrayList<T>) :
+    Immutable<MutableIndexedListSet<T>> {
     val size: Int
         get() = list.size
 
@@ -31,20 +28,15 @@
 
     fun indexOf(element: T): Int = list.indexOf(element)
 
-    @Suppress("ReplaceGetOrSet")
-    fun elementAt(index: Int): T = list.get(index)
+    @Suppress("ReplaceGetOrSet") fun elementAt(index: Int): T = list.get(index)
 
     override fun toMutable(): MutableIndexedListSet<T> = MutableIndexedListSet(this)
 
     override fun toString(): String = list.toString()
 }
 
-/**
- * Mutable set with index-based access, implemented using a list.
- */
-class MutableIndexedListSet<T>(
-    list: ArrayList<T> = ArrayList()
-) : IndexedListSet<T>(list) {
+/** Mutable set with index-based access, implemented using a list. */
+class MutableIndexedListSet<T>(list: ArrayList<T> = ArrayList()) : IndexedListSet<T>(list) {
     constructor(indexedListSet: IndexedListSet<T>) : this(ArrayList(indexedListSet.list))
 
     fun add(element: T): Boolean =
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedListSetExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedListSetExtensions.kt
index 13fc141..2634b53 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedListSetExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedListSetExtensions.kt
@@ -70,9 +70,7 @@
     accumulator: (Int, Int, T) -> Int
 ): Int {
     var value = initialValue
-    forEachIndexed { index, element ->
-        value = accumulator(value, index, element)
-    }
+    forEachIndexed { index, element -> value = accumulator(value, index, element) }
     return value
 }
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedMap.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedMap.kt
index 299cc89..873c9c8 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedMap.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedMap.kt
@@ -18,12 +18,9 @@
 
 import android.util.ArrayMap
 
-/**
- * Immutable map with index-based access.
- */
-sealed class IndexedMap<K, V>(
-    internal val map: ArrayMap<K, V>
-) : Immutable<MutableIndexedMap<K, V>> {
+/** Immutable map with index-based access. */
+sealed class IndexedMap<K, V>(internal val map: ArrayMap<K, V>) :
+    Immutable<MutableIndexedMap<K, V>> {
     val size: Int
         get() = map.size
 
@@ -31,8 +28,7 @@
 
     operator fun contains(key: K): Boolean = map.containsKey(key)
 
-    @Suppress("ReplaceGetOrSet")
-    operator fun get(key: K): V? = map.get(key)
+    @Suppress("ReplaceGetOrSet") operator fun get(key: K): V? = map.get(key)
 
     fun indexOfKey(key: K): Int = map.indexOfKey(key)
 
@@ -45,12 +41,8 @@
     override fun toString(): String = map.toString()
 }
 
-/**
- * Mutable map with index-based access.
- */
-class MutableIndexedMap<K, V>(
-    map: ArrayMap<K, V> = ArrayMap()
-) : IndexedMap<K, V>(map) {
+/** Mutable map with index-based access. */
+class MutableIndexedMap<K, V>(map: ArrayMap<K, V> = ArrayMap()) : IndexedMap<K, V>(map) {
     constructor(indexedMap: IndexedMap<K, V>) : this(ArrayMap(indexedMap.map))
 
     fun put(key: K, value: V): V? = map.put(key, value)
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedMapExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedMapExtensions.kt
index 69f1779c..48637cc 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedMapExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedMapExtensions.kt
@@ -36,7 +36,9 @@
 
 inline fun <K, V, R> IndexedMap<K, V>.firstNotNullOfOrNullIndexed(transform: (Int, K, V) -> R): R? {
     forEachIndexed { index, key, value ->
-        transform(index, key, value)?.let { return it }
+        transform(index, key, value)?.let {
+            return it
+        }
     }
     return null
 }
@@ -75,9 +77,7 @@
     destination: C,
     transform: (Int, K, V) -> R,
 ): C {
-    forEachIndexed { index, key, value ->
-        transform(index, key, value).let { destination += it }
-    }
+    forEachIndexed { index, key, value -> transform(index, key, value).let { destination += it } }
     return destination
 }
 
@@ -85,14 +85,14 @@
     destination: C,
     transform: (Int, K, V) -> R?
 ): C {
-    forEachIndexed { index, key, value ->
-        transform(index, key, value)?.let { destination += it }
-    }
+    forEachIndexed { index, key, value -> transform(index, key, value)?.let { destination += it } }
     return destination
 }
 
 inline fun <K, V> MutableIndexedMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
-    get(key)?.let { return it }
+    get(key)?.let {
+        return it
+    }
     return defaultValue().also { put(key, it) }
 }
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedReferenceMap.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedReferenceMap.kt
index ff76a47..6fe4718 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedReferenceMap.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedReferenceMap.kt
@@ -33,8 +33,7 @@
 
     operator fun contains(key: K): Boolean = map.containsKey(key)
 
-    @Suppress("ReplaceGetOrSet")
-    operator fun get(key: K): I? = map.get(key)?.get()
+    @Suppress("ReplaceGetOrSet") operator fun get(key: K): I? = map.get(key)?.get()
 
     fun indexOfKey(key: K): Int = map.indexOfKey(key)
 
@@ -55,7 +54,9 @@
 class MutableIndexedReferenceMap<K, I : Immutable<M>, M : I>(
     map: ArrayMap<K, MutableReference<I, M>> = ArrayMap()
 ) : IndexedReferenceMap<K, I, M>(map) {
-    constructor(indexedReferenceMap: IndexedReferenceMap<K, I, M>) : this(
+    constructor(
+        indexedReferenceMap: IndexedReferenceMap<K, I, M>
+    ) : this(
         ArrayMap(indexedReferenceMap.map).apply {
             for (i in 0 until size) {
                 setValueAt(i, valueAt(i).toImmutable())
@@ -63,8 +64,7 @@
         }
     )
 
-    @Suppress("ReplaceGetOrSet")
-    fun mutate(key: K): M? = map.get(key)?.mutate()
+    @Suppress("ReplaceGetOrSet") fun mutate(key: K): M? = map.get(key)?.mutate()
 
     fun put(key: K, value: M): I? = map.put(key, MutableReference(value))?.get()
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedReferenceMapExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedReferenceMapExtensions.kt
index 22b4d52..43a902b 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedReferenceMapExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedReferenceMapExtensions.kt
@@ -72,7 +72,9 @@
     key: K,
     defaultValue: () -> M
 ): M {
-    mutate(key)?.let { return it }
+    mutate(key)?.let {
+        return it
+    }
     return defaultValue().also { put(key, it) }
 }
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedSet.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedSet.kt
index 547e56c..cbc24b1 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedSet.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedSet.kt
@@ -18,12 +18,8 @@
 
 import android.util.ArraySet
 
-/**
- * Immutable set with index-based access.
- */
-sealed class IndexedSet<T>(
-    internal val set: ArraySet<T>
-) : Immutable<MutableIndexedSet<T>> {
+/** Immutable set with index-based access. */
+sealed class IndexedSet<T>(internal val set: ArraySet<T>) : Immutable<MutableIndexedSet<T>> {
     val size: Int
         get() = set.size
 
@@ -40,12 +36,8 @@
     override fun toString(): String = set.toString()
 }
 
-/**
- * Mutable set with index-based access.
- */
-class MutableIndexedSet<T>(
-    set: ArraySet<T> = ArraySet()
-) : IndexedSet<T>(set) {
+/** Mutable set with index-based access. */
+class MutableIndexedSet<T>(set: ArraySet<T> = ArraySet()) : IndexedSet<T>(set) {
     constructor(indexedSet: IndexedSet<T>) : this(ArraySet(indexedSet.set))
 
     fun add(element: T): Boolean = set.add(element)
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IntMap.kt b/services/permission/java/com/android/server/permission/access/immutable/IntMap.kt
index 7ed29e8..e9a405f 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IntMap.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IntMap.kt
@@ -18,12 +18,8 @@
 
 import android.util.SparseArray
 
-/**
- * Immutable map with index-based access and [Int] keys.
- */
-sealed class IntMap<T>(
-    internal val array: SparseArray<T>
-) : Immutable<MutableIntMap<T>> {
+/** Immutable map with index-based access and [Int] keys. */
+sealed class IntMap<T>(internal val array: SparseArray<T>) : Immutable<MutableIntMap<T>> {
     val size: Int
         get() = array.size()
 
@@ -44,12 +40,8 @@
     override fun toString(): String = array.toString()
 }
 
-/**
- * Mutable map with index-based access and [Int] keys.
- */
-class MutableIntMap<T>(
-    array: SparseArray<T> = SparseArray()
-) : IntMap<T>(array) {
+/** Mutable map with index-based access and [Int] keys. */
+class MutableIntMap<T>(array: SparseArray<T> = SparseArray()) : IntMap<T>(array) {
     constructor(intMap: IntMap<T>) : this(intMap.array.clone())
 
     fun put(key: Int, value: T): T? = array.putReturnOld(key, value)
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IntMapExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IntMapExtensions.kt
index 9aa0a41..09d7319 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IntMapExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IntMapExtensions.kt
@@ -36,7 +36,9 @@
 
 inline fun <T, R> IntMap<T>.firstNotNullOfOrNullIndexed(transform: (Int, Int, T) -> R): R? {
     forEachIndexed { index, key, value ->
-        transform(index, key, value)?.let { return it }
+        transform(index, key, value)?.let {
+            return it
+        }
     }
     return null
 }
@@ -72,7 +74,9 @@
 }
 
 inline fun <T> MutableIntMap<T>.getOrPut(key: Int, defaultValue: () -> T): T {
-    get(key)?.let { return it }
+    get(key)?.let {
+        return it
+    }
     return defaultValue().also { put(key, it) }
 }
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IntReferenceMap.kt b/services/permission/java/com/android/server/permission/access/immutable/IntReferenceMap.kt
index 160b227..3f26517 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IntReferenceMap.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IntReferenceMap.kt
@@ -33,8 +33,7 @@
 
     operator fun contains(key: Int): Boolean = array.contains(key)
 
-    @Suppress("ReplaceGetOrSet")
-    operator fun get(key: Int): I? = array.get(key)?.get()
+    @Suppress("ReplaceGetOrSet") operator fun get(key: Int): I? = array.get(key)?.get()
 
     fun indexOfKey(key: Int): Int = array.indexOfKey(key)
 
@@ -55,7 +54,9 @@
 class MutableIntReferenceMap<I : Immutable<M>, M : I>(
     array: SparseArray<MutableReference<I, M>> = SparseArray()
 ) : IntReferenceMap<I, M>(array) {
-    constructor(intReferenceMap: IntReferenceMap<I, M>) : this(
+    constructor(
+        intReferenceMap: IntReferenceMap<I, M>
+    ) : this(
         intReferenceMap.array.clone().apply {
             for (i in 0 until size()) {
                 setValueAt(i, valueAt(i).toImmutable())
@@ -63,8 +64,7 @@
         }
     )
 
-    @Suppress("ReplaceGetOrSet")
-    fun mutate(key: Int): M? = array.get(key)?.mutate()
+    @Suppress("ReplaceGetOrSet") fun mutate(key: Int): M? = array.get(key)?.mutate()
 
     fun put(key: Int, value: M): I? = array.putReturnOld(key, MutableReference(value))?.get()
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IntReferenceMapExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IntReferenceMapExtensions.kt
index 1ed4f8a..a1bab95 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IntReferenceMapExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IntReferenceMapExtensions.kt
@@ -72,7 +72,9 @@
     key: Int,
     defaultValue: () -> M
 ): M {
-    mutate(key)?.let { return it }
+    mutate(key)?.let {
+        return it
+    }
     return defaultValue().also { put(key, it) }
 }
 
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IntSet.kt b/services/permission/java/com/android/server/permission/access/immutable/IntSet.kt
index 21f2af2..1254797 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IntSet.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IntSet.kt
@@ -18,12 +18,8 @@
 
 import android.util.SparseBooleanArray
 
-/**
- * Immutable set with index-based access and [Int] elements.
- */
-sealed class IntSet(
-    internal val array: SparseBooleanArray
-) : Immutable<MutableIntSet> {
+/** Immutable set with index-based access and [Int] elements. */
+sealed class IntSet(internal val array: SparseBooleanArray) : Immutable<MutableIntSet> {
     val size: Int
         get() = array.size()
 
@@ -40,12 +36,8 @@
     override fun toString(): String = array.toString()
 }
 
-/**
- * Mutable set with index-based access and [Int] elements.
- */
-class MutableIntSet(
-    array: SparseBooleanArray = SparseBooleanArray()
-) : IntSet(array) {
+/** Mutable set with index-based access and [Int] elements. */
+class MutableIntSet(array: SparseBooleanArray = SparseBooleanArray()) : IntSet(array) {
     constructor(intSet: IntSet) : this(intSet.array.clone())
 
     fun add(element: Int): Boolean =
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IntSetExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IntSetExtensions.kt
index 163ebbf..9d0d14f 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IntSetExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IntSetExtensions.kt
@@ -66,7 +66,7 @@
 
 operator fun IntSet.plus(element: Int): MutableIntSet = toMutable().apply { this += element }
 
-fun MutableIntSet(values: IntArray): MutableIntSet = MutableIntSet().apply{ this += values }
+fun MutableIntSet(values: IntArray): MutableIntSet = MutableIntSet().apply { this += values }
 
 operator fun MutableIntSet.plusAssign(element: Int) {
     array.put(element, true)
diff --git a/services/permission/java/com/android/server/permission/access/immutable/MutableReference.kt b/services/permission/java/com/android/server/permission/access/immutable/MutableReference.kt
index 171cfeb..471a71b 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/MutableReference.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/MutableReference.kt
@@ -27,21 +27,17 @@
  * exposed on the immutable interface of the data structure as a `getFoo` method, and the [mutate]
  * method exposed on the mutable interface of the data structure as a `mutateFoo` method. When the
  * data structure is mutated/copied, a new instance of this class should be obtained with
- * [toImmutable], which makes the wrapped reference immutable-only again and thus prevents
- * further modifications to a data structure accessed with its immutable interface.
+ * [toImmutable], which makes the wrapped reference immutable-only again and thus prevents further
+ * modifications to a data structure accessed with its immutable interface.
  *
  * @see MutableIndexedReferenceMap
  * @see MutableIntReferenceMap
  */
-class MutableReference<I : Immutable<M>, M : I> private constructor(
-    private var immutable: I,
-    private var mutable: M?
-) {
+class MutableReference<I : Immutable<M>, M : I>
+private constructor(private var immutable: I, private var mutable: M?) {
     constructor(mutable: M) : this(mutable, mutable)
 
-    /**
-     * Return an immutable reference to the wrapped mutable data structure.
-     */
+    /** Return an immutable reference to the wrapped mutable data structure. */
     fun get(): I = immutable
 
     /**
@@ -50,7 +46,9 @@
      * already mutable.
      */
     fun mutate(): M {
-        mutable?.let { return it }
+        mutable?.let {
+            return it
+        }
         return immutable.toMutable().also {
             immutable = it
             mutable = it
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionMigration.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionMigration.kt
index 691ed8f..2983895 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionMigration.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionMigration.kt
@@ -23,9 +23,7 @@
 import com.android.server.permission.access.util.PackageVersionMigration
 import com.android.server.pm.permission.PermissionMigrationHelper
 
-/**
- * This class migrate legacy permissions to unified permission subsystem
- */
+/** This class migrate legacy permissions to unified permission subsystem */
 class AppIdPermissionMigration {
     internal fun migrateSystemState(state: MutableAccessState) {
         val legacyPermissionsManager =
@@ -34,10 +32,15 @@
             return
         }
 
-        migratePermissions(state.mutateSystemState().mutatePermissions(),
-            legacyPermissionsManager.legacyPermissions)
-        migratePermissions(state.mutateSystemState().mutatePermissionTrees(),
-            legacyPermissionsManager.legacyPermissionTrees, true)
+        migratePermissions(
+            state.mutateSystemState().mutatePermissions(),
+            legacyPermissionsManager.legacyPermissions
+        )
+        migratePermissions(
+            state.mutateSystemState().mutatePermissionTrees(),
+            legacyPermissionsManager.legacyPermissionTrees,
+            true
+        )
     }
 
     private fun migratePermissions(
@@ -46,14 +49,15 @@
         isPermissionTree: Boolean = false
     ) {
         legacyPermissions.forEach { (_, legacyPermission) ->
-            val permission = Permission(
-                legacyPermission.permissionInfo, false, legacyPermission.type, 0
-            )
+            val permission =
+                Permission(legacyPermission.permissionInfo, false, legacyPermission.type, 0)
             permissions[permission.name] = permission
             if (DEBUG_MIGRATION) {
-                Slog.v(LOG_TAG, "Migrated permission: ${permission.name}, type: " +
-                    "${permission.type}, appId: ${permission.appId}, protectionLevel: " +
-                    "${permission.protectionLevel}, tree: $isPermissionTree"
+                Slog.v(
+                    LOG_TAG,
+                    "Migrated permission: ${permission.name}, type: " +
+                        "${permission.type}, appId: ${permission.appId}, protectionLevel: " +
+                        "${permission.protectionLevel}, tree: $isPermissionTree"
                 )
             }
         }
@@ -81,25 +85,23 @@
 
             val permissionFlags = MutableIndexedMap<String, Int>()
             appIdPermissionFlags[appId] = permissionFlags
-            legacyPermissionStates.forEach forEachPermission@ {
+            legacyPermissionStates.forEach forEachPermission@{
                 (permissionName, legacyPermissionState) ->
                 val permission = state.systemState.permissions[permissionName]
                 if (permission == null) {
                     Slog.w(
-                        LOG_TAG, "Dropping unknown permission $permissionName for app ID $appId" +
+                        LOG_TAG,
+                        "Dropping unknown permission $permissionName for app ID $appId" +
                             " when migrating permission state"
                     )
                     return@forEachPermission
                 }
-                permissionFlags[permissionName] = migratePermissionFlags(
-                    permission, legacyPermissionState, appId, userId
-                )
+                permissionFlags[permissionName] =
+                    migratePermissionFlags(permission, legacyPermissionState, appId, userId)
             }
 
             val packageVersions = userState.mutatePackageVersions()
-            packageNames.forEachIndexed { _, packageName ->
-                packageVersions[packageName] = version
-            }
+            packageNames.forEachIndexed { _, packageName -> packageVersions[packageName] = version }
         }
     }
 
@@ -109,29 +111,35 @@
         appId: Int,
         userId: Int
     ): Int {
-        var flags = when {
-            permission.isNormal -> if (legacyPermissionState.isGranted) {
-                PermissionFlags.INSTALL_GRANTED
-            } else {
-                PermissionFlags.INSTALL_REVOKED
-            }
-            permission.isSignature || permission.isInternal ->
-                if (legacyPermissionState.isGranted) {
-                    if (permission.isDevelopment || permission.isRole) {
-                        PermissionFlags.PROTECTION_GRANTED or PermissionFlags.RUNTIME_GRANTED
+        var flags =
+            when {
+                permission.isNormal ->
+                    if (legacyPermissionState.isGranted) {
+                        PermissionFlags.INSTALL_GRANTED
                     } else {
-                        PermissionFlags.PROTECTION_GRANTED
+                        PermissionFlags.INSTALL_REVOKED
                     }
-                } else {
-                    0
-                }
-            permission.isRuntime ->
-                if (legacyPermissionState.isGranted) PermissionFlags.RUNTIME_GRANTED else 0
-            else -> 0
-        }
-        flags = PermissionFlags.updateFlags(
-            permission, flags, legacyPermissionState.flags, legacyPermissionState.flags
-        )
+                permission.isSignature || permission.isInternal ->
+                    if (legacyPermissionState.isGranted) {
+                        if (permission.isDevelopment || permission.isRole) {
+                            PermissionFlags.PROTECTION_GRANTED or PermissionFlags.RUNTIME_GRANTED
+                        } else {
+                            PermissionFlags.PROTECTION_GRANTED
+                        }
+                    } else {
+                        0
+                    }
+                permission.isRuntime ->
+                    if (legacyPermissionState.isGranted) PermissionFlags.RUNTIME_GRANTED else 0
+                else -> 0
+            }
+        flags =
+            PermissionFlags.updateFlags(
+                permission,
+                flags,
+                legacyPermissionState.flags,
+                legacyPermissionState.flags
+            )
         if (DEBUG_MIGRATION) {
             val oldFlagString = PermissionFlags.apiFlagsToString(legacyPermissionState.flags)
             val newFlagString = PermissionFlags.toString(flags)
@@ -139,7 +147,8 @@
             val newGrantState = PermissionFlags.isPermissionGranted(flags)
             val flagsMismatch = legacyPermissionState.flags != PermissionFlags.toApiFlags(flags)
             Slog.v(
-                LOG_TAG, "Migrated appId: $appId, permission: " +
+                LOG_TAG,
+                "Migrated appId: $appId, permission: " +
                     "${permission.name}, user: $userId, oldGrantState: $oldGrantState" +
                     ", oldFlags: $oldFlagString, newFlags: $newFlagString, grantMismatch: " +
                     "${oldGrantState != newGrantState}, flagsMismatch: $flagsMismatch"
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
index 2c8175b..1f40f01 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
@@ -57,11 +57,12 @@
         isPermissionTree: Boolean
     ) {
         val systemState = state.mutateSystemState(WriteMode.NONE)
-        val permissions = if (isPermissionTree) {
-            systemState.mutatePermissionTrees()
-        } else {
-            systemState.mutatePermissions()
-        }
+        val permissions =
+            if (isPermissionTree) {
+                systemState.mutatePermissionTrees()
+            } else {
+                systemState.mutatePermissions()
+            }
         forEachTag {
             when (val tagName = tagName) {
                 TAG_PERMISSION -> parsePermission(permissions)
@@ -71,10 +72,13 @@
         permissions.forEachReversedIndexed { permissionIndex, _, permission ->
             val packageName = permission.packageName
             val externalState = state.externalState
-            if (packageName !in externalState.packageStates &&
-                packageName !in externalState.disabledSystemPackageStates) {
+            if (
+                packageName !in externalState.packageStates &&
+                    packageName !in externalState.disabledSystemPackageStates
+            ) {
                 Slog.w(
-                    LOG_TAG, "Dropping permission ${permission.name} from unknown package" +
+                    LOG_TAG,
+                    "Dropping permission ${permission.name} from unknown package" +
                         " $packageName when parsing permissions"
                 )
                 permissions.removeAt(permissionIndex)
@@ -88,11 +92,12 @@
     ) {
         val name = getAttributeValueOrThrow(ATTR_NAME).intern()
         @Suppress("DEPRECATION")
-        val permissionInfo = PermissionInfo().apply {
-            this.name = name
-            packageName = getAttributeValueOrThrow(ATTR_PACKAGE_NAME).intern()
-            protectionLevel = getAttributeIntHexOrThrow(ATTR_PROTECTION_LEVEL)
-        }
+        val permissionInfo =
+            PermissionInfo().apply {
+                this.name = name
+                packageName = getAttributeValueOrThrow(ATTR_PACKAGE_NAME).intern()
+                protectionLevel = getAttributeIntHexOrThrow(ATTR_PROTECTION_LEVEL)
+            }
         val type = getAttributeIntOrThrow(ATTR_TYPE)
         when (type) {
             Permission.TYPE_MANIFEST -> {}
@@ -125,15 +130,14 @@
         tagName: String,
         permissions: IndexedMap<String, Permission>
     ) {
-        tag(tagName) {
-            permissions.forEachIndexed { _, _, it -> serializePermission(it) }
-        }
+        tag(tagName) { permissions.forEachIndexed { _, _, it -> serializePermission(it) } }
     }
 
     private fun BinaryXmlSerializer.serializePermission(permission: Permission) {
         val type = permission.type
         when (type) {
-            Permission.TYPE_MANIFEST, Permission.TYPE_DYNAMIC -> {}
+            Permission.TYPE_MANIFEST,
+            Permission.TYPE_DYNAMIC -> {}
             Permission.TYPE_CONFIG -> return
             else -> {
                 Slog.w(LOG_TAG, "Skipping serializing permission $name with unknown type $type")
@@ -228,11 +232,12 @@
         tag(TAG_PERMISSION) {
             attributeInterned(ATTR_NAME, name)
             // Never serialize one-time permissions as granted.
-            val serializedFlags = if (flags.hasBits(PermissionFlags.ONE_TIME)) {
-                flags andInv PermissionFlags.RUNTIME_GRANTED
-            } else {
-                flags
-            }
+            val serializedFlags =
+                if (flags.hasBits(PermissionFlags.ONE_TIME)) {
+                    flags andInv PermissionFlags.RUNTIME_GRANTED
+                } else {
+                    flags
+                }
             attributeInt(ATTR_FLAGS, serializedFlags)
         }
     }
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 345f101..08ba753 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -55,7 +55,8 @@
 
     @Volatile
     private var onPermissionFlagsChangedListeners:
-        IndexedListSet<OnPermissionFlagsChangedListener> = MutableIndexedListSet()
+        IndexedListSet<OnPermissionFlagsChangedListener> =
+        MutableIndexedListSet()
     private val onPermissionFlagsChangedListenersLock = Any()
 
     private val privilegedPermissionAllowlistViolations = MutableIndexedSet<String>()
@@ -73,30 +74,37 @@
     override fun MutateStateScope.onInitialized() {
         newState.externalState.configPermissions.forEach { (permissionName, permissionEntry) ->
             val oldPermission = newState.systemState.permissions[permissionName]
-            val newPermission = if (oldPermission != null) {
-                if (permissionEntry.gids != null) {
-                    oldPermission.copy(
-                        gids = permissionEntry.gids, areGidsPerUser = permissionEntry.perUser
-                    )
+            val newPermission =
+                if (oldPermission != null) {
+                    if (permissionEntry.gids != null) {
+                        oldPermission.copy(
+                            gids = permissionEntry.gids,
+                            areGidsPerUser = permissionEntry.perUser
+                        )
+                    } else {
+                        return@forEach
+                    }
                 } else {
-                    return@forEach
+                    @Suppress("DEPRECATION")
+                    val permissionInfo =
+                        PermissionInfo().apply {
+                            name = permissionName
+                            packageName = PLATFORM_PACKAGE_NAME
+                            protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
+                        }
+                    if (permissionEntry.gids != null) {
+                        Permission(
+                            permissionInfo,
+                            false,
+                            Permission.TYPE_CONFIG,
+                            0,
+                            permissionEntry.gids,
+                            permissionEntry.perUser
+                        )
+                    } else {
+                        Permission(permissionInfo, false, Permission.TYPE_CONFIG, 0)
+                    }
                 }
-            } else {
-                @Suppress("DEPRECATION")
-                val permissionInfo = PermissionInfo().apply {
-                    name = permissionName
-                    packageName = PLATFORM_PACKAGE_NAME
-                    protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
-                }
-                if (permissionEntry.gids != null) {
-                    Permission(
-                        permissionInfo, false, Permission.TYPE_CONFIG, 0, permissionEntry.gids,
-                        permissionEntry.perUser
-                    )
-                } else {
-                    Permission(permissionInfo, false, Permission.TYPE_CONFIG, 0)
-                }
-            }
             newState.mutateSystemState().mutatePermissions()[permissionName] = newPermission
         }
     }
@@ -200,30 +208,32 @@
         val androidPackage = packageState.androidPackage ?: return
         val appId = packageState.appId
         androidPackage.requestedPermissions.forEach { permissionName ->
-            val permission = newState.systemState.permissions[permissionName]
-                ?: return@forEach
+            val permission = newState.systemState.permissions[permissionName] ?: return@forEach
             if (!permission.isHardOrSoftRestricted) {
                 return@forEach
             }
-            val isRequestedBySystemPackage = anyPackageInAppId(appId) {
-                it.isSystem && permissionName in it.androidPackage!!.requestedPermissions
-            }
+            val isRequestedBySystemPackage =
+                anyPackageInAppId(appId) {
+                    it.isSystem && permissionName in it.androidPackage!!.requestedPermissions
+                }
             if (isRequestedBySystemPackage) {
                 return@forEach
             }
             val oldFlags = getPermissionFlags(appId, userId, permissionName)
             var newFlags = oldFlags andInv PermissionFlags.UPGRADE_EXEMPT
             val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
-            newFlags = if (permission.isHardRestricted && !isExempt) {
-                newFlags or PermissionFlags.RESTRICTION_REVOKED
-            } else {
-                newFlags andInv PermissionFlags.RESTRICTION_REVOKED
-            }
-            newFlags = if (permission.isSoftRestricted && !isExempt) {
-                newFlags or PermissionFlags.SOFT_RESTRICTED
-            } else {
-                newFlags andInv PermissionFlags.SOFT_RESTRICTED
-            }
+            newFlags =
+                if (permission.isHardRestricted && !isExempt) {
+                    newFlags or PermissionFlags.RESTRICTION_REVOKED
+                } else {
+                    newFlags andInv PermissionFlags.RESTRICTION_REVOKED
+                }
+            newFlags =
+                if (permission.isSoftRestricted && !isExempt) {
+                    newFlags or PermissionFlags.SOFT_RESTRICTED
+                } else {
+                    newFlags andInv PermissionFlags.SOFT_RESTRICTED
+                }
             setPermissionFlags(appId, userId, permissionName, newFlags)
         }
     }
@@ -243,15 +253,15 @@
         val androidPackage = packageState.androidPackage ?: return
         val appId = packageState.appId
         androidPackage.requestedPermissions.forEach { permissionName ->
-            val permission = newState.systemState.permissions[permissionName]
-                ?: return@forEach
+            val permission = newState.systemState.permissions[permissionName] ?: return@forEach
             if (!permission.isRuntime || permission.isRemoved) {
                 return@forEach
             }
-            val isRequestedByOtherPackages = anyPackageInAppId(appId) {
-                it.packageName != packageName &&
-                    permissionName in it.androidPackage!!.requestedPermissions
-            }
+            val isRequestedByOtherPackages =
+                anyPackageInAppId(appId) {
+                    it.packageName != packageName &&
+                        permissionName in it.androidPackage!!.requestedPermissions
+                }
             if (isRequestedByOtherPackages) {
                 return@forEach
             }
@@ -260,13 +270,15 @@
                 return@forEach
             }
             var newFlags = oldFlags
-            newFlags = if (
-                newFlags.hasBits(PermissionFlags.ROLE) || newFlags.hasBits(PermissionFlags.PREGRANT)
-            ) {
-                newFlags or PermissionFlags.RUNTIME_GRANTED
-            } else {
-                newFlags andInv PermissionFlags.RUNTIME_GRANTED
-            }
+            newFlags =
+                if (
+                    newFlags.hasBits(PermissionFlags.ROLE) ||
+                        newFlags.hasBits(PermissionFlags.PREGRANT)
+                ) {
+                    newFlags or PermissionFlags.RUNTIME_GRANTED
+                } else {
+                    newFlags andInv PermissionFlags.RUNTIME_GRANTED
+                }
             newFlags = newFlags andInv USER_SETTABLE_MASK
             if (newFlags.hasBits(PermissionFlags.LEGACY_GRANTED)) {
                 newFlags = newFlags or PermissionFlags.IMPLICIT
@@ -285,24 +297,32 @@
             if (!canAdoptPermissions(packageName, originalPackageName)) {
                 return@forEachIndexed
             }
-            newState.systemState.permissions.forEachIndexed permissions@ {
-                permissionIndex, permissionName, oldPermission ->
+            newState.systemState.permissions.forEachIndexed permissions@{
+                permissionIndex,
+                permissionName,
+                oldPermission ->
                 if (oldPermission.packageName != originalPackageName) {
                     return@permissions
                 }
                 @Suppress("DEPRECATION")
-                val newPermissionInfo = PermissionInfo().apply {
-                    name = oldPermission.permissionInfo.name
-                    this.packageName = packageName
-                    protectionLevel = oldPermission.permissionInfo.protectionLevel
-                }
+                val newPermissionInfo =
+                    PermissionInfo().apply {
+                        name = oldPermission.permissionInfo.name
+                        this.packageName = packageName
+                        protectionLevel = oldPermission.permissionInfo.protectionLevel
+                    }
                 // Different from the old implementation, which removes the GIDs upon permission
                 // adoption, but adds them back on the next boot, we now just consistently keep the
                 // GIDs.
-                val newPermission = oldPermission.copy(
-                    permissionInfo = newPermissionInfo, isReconciled = false, appId = 0
-                )
-                newState.mutateSystemState().mutatePermissions()
+                val newPermission =
+                    oldPermission.copy(
+                        permissionInfo = newPermissionInfo,
+                        isReconciled = false,
+                        appId = 0
+                    )
+                newState
+                    .mutateSystemState()
+                    .mutatePermissions()
                     .putAt(permissionIndex, newPermission)
                 changedPermissionNames += permissionName
             }
@@ -313,18 +333,20 @@
         packageName: String,
         originalPackageName: String
     ): Boolean {
-        val originalPackageState = newState.externalState.packageStates[originalPackageName]
-            ?: return false
+        val originalPackageState =
+            newState.externalState.packageStates[originalPackageName] ?: return false
         if (!originalPackageState.isSystem) {
             Slog.w(
-                LOG_TAG, "Unable to adopt permissions from $originalPackageName to $packageName:" +
+                LOG_TAG,
+                "Unable to adopt permissions from $originalPackageName to $packageName:" +
                     " original package not in system partition"
             )
             return false
         }
         if (originalPackageState.androidPackage != null) {
             Slog.w(
-                LOG_TAG, "Unable to adopt permissions from $originalPackageName to $packageName:" +
+                LOG_TAG,
+                "Unable to adopt permissions from $originalPackageName to $packageName:" +
                     " original package still exists"
             )
             return false
@@ -339,20 +361,25 @@
         val isInstantApp = packageState.userStates.allIndexed { _, _, it -> it.isInstantApp }
         if (isInstantApp) {
             Slog.w(
-                LOG_TAG, "Ignoring permission groups declared in package" +
+                LOG_TAG,
+                "Ignoring permission groups declared in package" +
                     " ${packageState.packageName}: instant apps cannot declare permission groups"
             )
             return
         }
         packageState.androidPackage!!.permissionGroups.forEachIndexed { _, parsedPermissionGroup ->
-            val newPermissionGroup = PackageInfoUtils.generatePermissionGroupInfo(
-                parsedPermissionGroup, PackageManager.GET_META_DATA.toLong()
-            )!!
+            val newPermissionGroup =
+                PackageInfoUtils.generatePermissionGroupInfo(
+                    parsedPermissionGroup,
+                    PackageManager.GET_META_DATA.toLong()
+                )!!
             // TODO: Clear permission state on group take-over?
             val permissionGroupName = newPermissionGroup.name
             val oldPermissionGroup = newState.systemState.permissionGroups[permissionGroupName]
-            if (oldPermissionGroup != null &&
-                newPermissionGroup.packageName != oldPermissionGroup.packageName) {
+            if (
+                oldPermissionGroup != null &&
+                    newPermissionGroup.packageName != oldPermissionGroup.packageName
+            ) {
                 val newPackageName = newPermissionGroup.packageName
                 val oldPackageName = oldPermissionGroup.packageName
                 // Different from the old implementation, which defines permission group on
@@ -361,7 +388,8 @@
                 // to permissions so that we no longer need to rely on the scan order.
                 if (!packageState.isSystem) {
                     Slog.w(
-                        LOG_TAG, "Ignoring permission group $permissionGroupName declared in" +
+                        LOG_TAG,
+                        "Ignoring permission group $permissionGroupName declared in" +
                             " package $newPackageName: already declared in another" +
                             " package $oldPackageName"
                     )
@@ -369,14 +397,16 @@
                 }
                 if (newState.externalState.packageStates[oldPackageName]?.isSystem == true) {
                     Slog.w(
-                        LOG_TAG, "Ignoring permission group $permissionGroupName declared in" +
+                        LOG_TAG,
+                        "Ignoring permission group $permissionGroupName declared in" +
                             " system package $newPackageName: already declared in another" +
                             " system package $oldPackageName"
                     )
                     return@forEachIndexed
                 }
                 Slog.w(
-                    LOG_TAG, "Overriding permission group $permissionGroupName with" +
+                    LOG_TAG,
+                    "Overriding permission group $permissionGroupName with" +
                         " new declaration in system package $newPackageName: originally" +
                         " declared in another package $oldPackageName"
                 )
@@ -393,20 +423,23 @@
         val androidPackage = packageState.androidPackage!!
         // This may not be the same package as the old permission because the old permission owner
         // can be different, hence using this somewhat strange name to prevent misuse.
-        val oldNewPackage = oldState.externalState.packageStates[packageState.packageName]
-            ?.androidPackage
-        val isPackageSigningChanged = oldNewPackage != null &&
-                androidPackage.signingDetails != oldNewPackage.signingDetails
+        val oldNewPackage =
+            oldState.externalState.packageStates[packageState.packageName]?.androidPackage
+        val isPackageSigningChanged =
+            oldNewPackage != null && androidPackage.signingDetails != oldNewPackage.signingDetails
         androidPackage.permissions.forEachIndexed { _, parsedPermission ->
-            val newPermissionInfo = PackageInfoUtils.generatePermissionInfo(
-                parsedPermission, PackageManager.GET_META_DATA.toLong()
-            )!!
+            val newPermissionInfo =
+                PackageInfoUtils.generatePermissionInfo(
+                    parsedPermission,
+                    PackageManager.GET_META_DATA.toLong()
+                )!!
             val permissionName = newPermissionInfo.name
-            val oldPermission = if (parsedPermission.isTree) {
-                newState.systemState.permissionTrees[permissionName]
-            } else {
-                newState.systemState.permissions[permissionName]
-            }
+            val oldPermission =
+                if (parsedPermission.isTree) {
+                    newState.systemState.permissionTrees[permissionName]
+                } else {
+                    newState.systemState.permissions[permissionName]
+                }
             // Different from the old implementation, which may add an (incomplete) signature
             // permission inside another package's permission tree, we now consistently ignore such
             // permissions.
@@ -414,128 +447,152 @@
             val newPackageName = newPermissionInfo.packageName
             if (permissionTree != null && newPackageName != permissionTree.packageName) {
                 Slog.w(
-                    LOG_TAG, "Ignoring permission $permissionName declared in package" +
+                    LOG_TAG,
+                    "Ignoring permission $permissionName declared in package" +
                         " $newPackageName: base permission tree ${permissionTree.name} is" +
                         " declared in another package ${permissionTree.packageName}"
                 )
                 return@forEachIndexed
             }
-            val newPermission = if (oldPermission != null &&
-                newPackageName != oldPermission.packageName) {
-                val oldPackageName = oldPermission.packageName
-                // Only allow system apps to redefine non-system permissions.
-                if (!packageState.isSystem) {
-                    Slog.w(
-                        LOG_TAG, "Ignoring permission $permissionName declared in package" +
-                            " $newPackageName: already declared in another package" +
-                            " $oldPackageName"
-                    )
-                    return@forEachIndexed
-                }
-                if (oldPermission.type == Permission.TYPE_CONFIG && !oldPermission.isReconciled) {
-                    // It's a config permission and has no owner, take ownership now.
-                    oldPermission.copy(
-                        permissionInfo = newPermissionInfo, isReconciled = true,
-                        type = Permission.TYPE_MANIFEST, appId = packageState.appId
-                    )
-                } else if (newState.externalState.packageStates[oldPackageName]?.isSystem != true) {
-                    Slog.w(
-                        LOG_TAG, "Overriding permission $permissionName with new declaration in" +
-                            " system package $newPackageName: originally declared in another" +
-                            " package $oldPackageName"
-                    )
-                    // Remove permission state on owner change.
-                    newState.externalState.userIds.forEachIndexed { _, userId ->
-                        newState.externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
-                            setPermissionFlags(appId, userId, permissionName, 0)
-                        }
-                    }
-                    // Different from the old implementation, which removes the GIDs upon permission
-                    // override, but adds them back on the next boot, we now just consistently keep
-                    // the GIDs.
-                    Permission(
-                        newPermissionInfo, true, Permission.TYPE_MANIFEST, packageState.appId,
-                        oldPermission.gids, oldPermission.areGidsPerUser
-                    )
-                } else {
-                    Slog.w(
-                        LOG_TAG, "Ignoring permission $permissionName declared in system package" +
-                            " $newPackageName: already declared in another system package" +
-                            " $oldPackageName"
-                    )
-                    return@forEachIndexed
-                }
-            } else {
-                if (oldPermission != null && oldPermission.isReconciled) {
-                    val isPermissionGroupChanged = newPermissionInfo.isRuntime &&
-                        newPermissionInfo.group != null &&
-                        newPermissionInfo.group != oldPermission.groupName
-                    val isPermissionProtectionChanged =
-                        oldPermission.type != Permission.TYPE_CONFIG && (
-                            (newPermissionInfo.isRuntime && !oldPermission.isRuntime) ||
-                                (newPermissionInfo.isInternal && !oldPermission.isInternal)
+            val newPermission =
+                if (oldPermission != null && newPackageName != oldPermission.packageName) {
+                    val oldPackageName = oldPermission.packageName
+                    // Only allow system apps to redefine non-system permissions.
+                    if (!packageState.isSystem) {
+                        Slog.w(
+                            LOG_TAG,
+                            "Ignoring permission $permissionName declared in package" +
+                                " $newPackageName: already declared in another package" +
+                                " $oldPackageName"
                         )
-                    if (isPermissionGroupChanged || isPermissionProtectionChanged) {
+                        return@forEachIndexed
+                    }
+                    if (
+                        oldPermission.type == Permission.TYPE_CONFIG && !oldPermission.isReconciled
+                    ) {
+                        // It's a config permission and has no owner, take ownership now.
+                        oldPermission.copy(
+                            permissionInfo = newPermissionInfo,
+                            isReconciled = true,
+                            type = Permission.TYPE_MANIFEST,
+                            appId = packageState.appId
+                        )
+                    } else if (
+                        newState.externalState.packageStates[oldPackageName]?.isSystem != true
+                    ) {
+                        Slog.w(
+                            LOG_TAG,
+                            "Overriding permission $permissionName with new declaration in" +
+                                " system package $newPackageName: originally declared in another" +
+                                " package $oldPackageName"
+                        )
+                        // Remove permission state on owner change.
                         newState.externalState.userIds.forEachIndexed { _, userId ->
                             newState.externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
-                                if (isPermissionGroupChanged) {
-                                    // We might auto-grant permissions if any permission of
-                                    // the group is already granted. Hence if the group of
-                                    // a granted permission changes we need to revoke it to
-                                    // avoid having permissions of the new group auto-granted.
-                                    Slog.w(
-                                        LOG_TAG, "Revoking runtime permission $permissionName for" +
-                                            " appId $appId and userId $userId as the permission" +
-                                            " group changed from ${oldPermission.groupName}" +
-                                            " to ${newPermissionInfo.group}"
-                                    )
-                                }
-                                if (isPermissionProtectionChanged) {
-                                    Slog.w(
-                                        LOG_TAG, "Revoking permission $permissionName for" +
-                                            " appId $appId and userId $userId as the permission" +
-                                            " protection changed."
-                                    )
-                                }
                                 setPermissionFlags(appId, userId, permissionName, 0)
                             }
                         }
+                        // Different from the old implementation, which removes the GIDs upon
+                        // permission
+                        // override, but adds them back on the next boot, we now just consistently
+                        // keep
+                        // the GIDs.
+                        Permission(
+                            newPermissionInfo,
+                            true,
+                            Permission.TYPE_MANIFEST,
+                            packageState.appId,
+                            oldPermission.gids,
+                            oldPermission.areGidsPerUser
+                        )
+                    } else {
+                        Slog.w(
+                            LOG_TAG,
+                            "Ignoring permission $permissionName declared in system package" +
+                                " $newPackageName: already declared in another system package" +
+                                " $oldPackageName"
+                        )
+                        return@forEachIndexed
+                    }
+                } else {
+                    if (oldPermission != null && oldPermission.isReconciled) {
+                        val isPermissionGroupChanged =
+                            newPermissionInfo.isRuntime &&
+                                newPermissionInfo.group != null &&
+                                newPermissionInfo.group != oldPermission.groupName
+                        val isPermissionProtectionChanged =
+                            oldPermission.type != Permission.TYPE_CONFIG &&
+                                ((newPermissionInfo.isRuntime && !oldPermission.isRuntime) ||
+                                    (newPermissionInfo.isInternal && !oldPermission.isInternal))
+                        if (isPermissionGroupChanged || isPermissionProtectionChanged) {
+                            newState.externalState.userIds.forEachIndexed { _, userId ->
+                                newState.externalState.appIdPackageNames.forEachIndexed {
+                                    _,
+                                    appId,
+                                    _ ->
+                                    if (isPermissionGroupChanged) {
+                                        // We might auto-grant permissions if any permission of
+                                        // the group is already granted. Hence if the group of
+                                        // a granted permission changes we need to revoke it to
+                                        // avoid having permissions of the new group auto-granted.
+                                        Slog.w(
+                                            LOG_TAG,
+                                            "Revoking runtime permission $permissionName for" +
+                                                " appId $appId and userId $userId as the permission" +
+                                                " group changed from ${oldPermission.groupName}" +
+                                                " to ${newPermissionInfo.group}"
+                                        )
+                                    }
+                                    if (isPermissionProtectionChanged) {
+                                        Slog.w(
+                                            LOG_TAG,
+                                            "Revoking permission $permissionName for" +
+                                                " appId $appId and userId $userId as the permission" +
+                                                " protection changed."
+                                        )
+                                    }
+                                    setPermissionFlags(appId, userId, permissionName, 0)
+                                }
+                            }
+                        }
+                    }
+
+                    // Different from the old implementation, which doesn't update the permission
+                    // definition upon app update, but does update it on the next boot, we now
+                    // consistently update the permission definition upon app update.
+                    @Suppress("IfThenToElvis")
+                    if (oldPermission != null) {
+                        oldPermission.copy(
+                            permissionInfo = newPermissionInfo,
+                            isReconciled = true,
+                            type = Permission.TYPE_MANIFEST,
+                            appId = packageState.appId
+                        )
+                    } else {
+                        Permission(
+                            newPermissionInfo,
+                            true,
+                            Permission.TYPE_MANIFEST,
+                            packageState.appId
+                        )
                     }
                 }
 
-                // Different from the old implementation, which doesn't update the permission
-                // definition upon app update, but does update it on the next boot, we now
-                // consistently update the permission definition upon app update.
-                @Suppress("IfThenToElvis")
-                if (oldPermission != null) {
-                    oldPermission.copy(
-                        permissionInfo = newPermissionInfo, isReconciled = true,
-                        type = Permission.TYPE_MANIFEST, appId = packageState.appId
-                    )
-                } else {
-                    Permission(
-                        newPermissionInfo, true, Permission.TYPE_MANIFEST, packageState.appId
-                    )
-                }
-            }
-
             if (parsedPermission.isTree) {
                 newState.mutateSystemState().mutatePermissionTrees()[permissionName] = newPermission
             } else {
                 newState.mutateSystemState().mutatePermissions()[permissionName] = newPermission
-                val isPermissionChanged = oldPermission == null ||
-                    newPackageName != oldPermission.packageName ||
-                    newPermission.protectionLevel != oldPermission.protectionLevel || (
-                        oldPermission.isReconciled && (
-                            (newPermission.isSignature && isPackageSigningChanged) || (
-                                newPermission.isKnownSigner &&
-                                    newPermission.knownCerts != oldPermission.knownCerts
-                            ) || (
-                                newPermission.isRuntime && newPermission.groupName != null &&
-                                    newPermission.groupName != oldPermission.groupName
-                            )
-                        )
-                    )
+                val isPermissionChanged =
+                    oldPermission == null ||
+                        newPackageName != oldPermission.packageName ||
+                        newPermission.protectionLevel != oldPermission.protectionLevel ||
+                        (oldPermission.isReconciled &&
+                            ((newPermission.isSignature && isPackageSigningChanged) ||
+                                (newPermission.isKnownSigner &&
+                                    newPermission.knownCerts != oldPermission.knownCerts) ||
+                                (newPermission.isRuntime &&
+                                    newPermission.groupName != null &&
+                                    newPermission.groupName != oldPermission.groupName)))
                 if (isPermissionChanged) {
                     changedPermissionNames += permissionName
                 }
@@ -552,39 +609,47 @@
         if (packageState != null && androidPackage == null) {
             return
         }
-        val disabledSystemPackage = newState.externalState.disabledSystemPackageStates[packageName]
-            ?.androidPackage
+        val disabledSystemPackage =
+            newState.externalState.disabledSystemPackageStates[packageName]?.androidPackage
         // Unlike in the previous implementation, we now also retain permission trees defined by
         // disabled system packages for consistency with permissions.
         newState.systemState.permissionTrees.forEachReversedIndexed {
-            permissionTreeIndex, permissionTreeName, permissionTree ->
-            if (permissionTree.packageName == packageName && (
-                packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
-                    it.isTree && it.name == permissionTreeName
-                }
-            ) && (
-                disabledSystemPackage?.permissions?.anyIndexed { _, it ->
-                    it.isTree && it.name == permissionTreeName
-                } != true
-            )) {
+            permissionTreeIndex,
+            permissionTreeName,
+            permissionTree ->
+            if (
+                permissionTree.packageName == packageName &&
+                    (packageState == null ||
+                        androidPackage!!.permissions.noneIndexed { _, it ->
+                            it.isTree && it.name == permissionTreeName
+                        }) &&
+                    (disabledSystemPackage?.permissions?.anyIndexed { _, it ->
+                        it.isTree && it.name == permissionTreeName
+                    } != true)
+            ) {
                 newState.mutateSystemState().mutatePermissionTrees().removeAt(permissionTreeIndex)
             }
         }
 
         newState.systemState.permissions.forEachReversedIndexed {
-            permissionIndex, permissionName, permission ->
+            permissionIndex,
+            permissionName,
+            permission ->
             val updatedPermission = updatePermissionIfDynamic(permission)
-            newState.mutateSystemState().mutatePermissions()
+            newState
+                .mutateSystemState()
+                .mutatePermissions()
                 .putAt(permissionIndex, updatedPermission)
-            if (updatedPermission.packageName == packageName && (
-                packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
-                    !it.isTree && it.name == permissionName
-                }
-            ) && (
-                disabledSystemPackage?.permissions?.anyIndexed { _, it ->
-                    !it.isTree && it.name == permissionName
-                } != true
-            )) {
+            if (
+                updatedPermission.packageName == packageName &&
+                    (packageState == null ||
+                        androidPackage!!.permissions.noneIndexed { _, it ->
+                            !it.isTree && it.name == permissionName
+                        }) &&
+                    (disabledSystemPackage?.permissions?.anyIndexed { _, it ->
+                        !it.isTree && it.name == permissionName
+                    } != true)
+            ) {
                 // Different from the old implementation where we keep the permission state if the
                 // permission is declared by a disabled system package (ag/15189282), we now
                 // shouldn't be notified when the updated system package is removed but the disabled
@@ -608,9 +673,12 @@
         val permissionTree = findPermissionTree(permission.name) ?: return permission
         @Suppress("DEPRECATION")
         return permission.copy(
-            permissionInfo = PermissionInfo(permission.permissionInfo).apply {
-                packageName = permissionTree.packageName
-            }, appId = permissionTree.appId, isReconciled = true
+            permissionInfo =
+                PermissionInfo(permission.permissionInfo).apply {
+                    packageName = permissionTree.packageName
+                },
+            appId = permissionTree.appId,
+            isReconciled = true
         )
     }
 
@@ -636,8 +704,9 @@
     }
 
     private fun MutateStateScope.revokePermissionsOnPackageUpdate(appId: Int) {
-        val hasOldPackage = appId in oldState.externalState.appIdPackageNames &&
-            anyPackageInAppId(appId, oldState) { true }
+        val hasOldPackage =
+            appId in oldState.externalState.appIdPackageNames &&
+                anyPackageInAppId(appId, oldState) { true }
         if (!hasOldPackage) {
             // Don't revoke anything if this isn't a package update, i.e. if information about the
             // old package isn't available. Notably, this also means skipping packages changed via
@@ -650,46 +719,58 @@
         // app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
         val oldTargetSdkVersion =
             reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, oldState) {
-                targetSdkVersion, packageState ->
+                targetSdkVersion,
+                packageState ->
                 targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
             }
         val newTargetSdkVersion =
             reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, newState) {
-                targetSdkVersion, packageState ->
+                targetSdkVersion,
+                packageState ->
                 targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
             }
         @Suppress("ConvertTwoComparisonsToRangeCheck")
-        val isTargetSdkVersionDowngraded = oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
-            newTargetSdkVersion < Build.VERSION_CODES.Q
+        val isTargetSdkVersionDowngraded =
+            oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
+                newTargetSdkVersion < Build.VERSION_CODES.Q
         @Suppress("ConvertTwoComparisonsToRangeCheck")
-        val isTargetSdkVersionUpgraded = oldTargetSdkVersion < Build.VERSION_CODES.Q &&
-            newTargetSdkVersion >= Build.VERSION_CODES.Q
-        val oldIsRequestLegacyExternalStorage = anyPackageInAppId(appId, oldState) {
-            it.androidPackage!!.isRequestLegacyExternalStorage
-        }
-        val newIsRequestLegacyExternalStorage = anyPackageInAppId(appId, newState) {
-            it.androidPackage!!.isRequestLegacyExternalStorage
-        }
-        val isNewlyRequestingLegacyExternalStorage = !isTargetSdkVersionUpgraded &&
-            !oldIsRequestLegacyExternalStorage && newIsRequestLegacyExternalStorage
-        val shouldRevokeStorageAndMediaPermissions = isNewlyRequestingLegacyExternalStorage ||
-            isTargetSdkVersionDowngraded
+        val isTargetSdkVersionUpgraded =
+            oldTargetSdkVersion < Build.VERSION_CODES.Q &&
+                newTargetSdkVersion >= Build.VERSION_CODES.Q
+        val oldIsRequestLegacyExternalStorage =
+            anyPackageInAppId(appId, oldState) {
+                it.androidPackage!!.isRequestLegacyExternalStorage
+            }
+        val newIsRequestLegacyExternalStorage =
+            anyPackageInAppId(appId, newState) {
+                it.androidPackage!!.isRequestLegacyExternalStorage
+            }
+        val isNewlyRequestingLegacyExternalStorage =
+            !isTargetSdkVersionUpgraded &&
+                !oldIsRequestLegacyExternalStorage &&
+                newIsRequestLegacyExternalStorage
+        val shouldRevokeStorageAndMediaPermissions =
+            isNewlyRequestingLegacyExternalStorage || isTargetSdkVersionDowngraded
         if (shouldRevokeStorageAndMediaPermissions) {
             newState.userStates.forEachIndexed { _, userId, userState ->
                 userState.appIdPermissionFlags[appId]?.forEachReversedIndexed {
-                    _, permissionName, oldFlags ->
+                    _,
+                    permissionName,
+                    oldFlags ->
                     // Do not revoke the permission during an upgrade if it's POLICY_FIXED or
                     // SYSTEM_FIXED. Otherwise the user cannot grant back the permission.
-                    if (permissionName in STORAGE_AND_MEDIA_PERMISSIONS &&
-                        oldFlags.hasBits(PermissionFlags.RUNTIME_GRANTED) &&
-                        !oldFlags.hasAnyBit(SYSTEM_OR_POLICY_FIXED_MASK)) {
+                    if (
+                        permissionName in STORAGE_AND_MEDIA_PERMISSIONS &&
+                            oldFlags.hasBits(PermissionFlags.RUNTIME_GRANTED) &&
+                            !oldFlags.hasAnyBit(SYSTEM_OR_POLICY_FIXED_MASK)
+                    ) {
                         Slog.v(
-                            LOG_TAG, "Revoking storage permission: $permissionName for appId: " +
+                            LOG_TAG,
+                            "Revoking storage permission: $permissionName for appId: " +
                                 " $appId and user: $userId"
                         )
-                        val newFlags = oldFlags andInv (
-                            PermissionFlags.RUNTIME_GRANTED or USER_SETTABLE_MASK
-                        )
+                        val newFlags =
+                            oldFlags andInv (PermissionFlags.RUNTIME_GRANTED or USER_SETTABLE_MASK)
                         setPermissionFlags(appId, userId, permissionName, newFlags)
                     }
                 }
@@ -704,9 +785,10 @@
         val externalState = newState.externalState
         externalState.userIds.forEachIndexed { _, userId ->
             externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
-                val isPermissionRequested = anyPackageInAppId(appId) {
-                    permissionName in it.androidPackage!!.requestedPermissions
-                }
+                val isPermissionRequested =
+                    anyPackageInAppId(appId) {
+                        permissionName in it.androidPackage!!.requestedPermissions
+                    }
                 if (isPermissionRequested) {
                     evaluatePermissionState(appId, userId, permissionName, installedPackageState)
                 }
@@ -720,7 +802,9 @@
     ) {
         newState.externalState.userIds.forEachIndexed { _, userId ->
             evaluateAllPermissionStatesForPackageAndUser(
-                packageState, userId, installedPackageState
+                packageState,
+                userId,
+                installedPackageState
             )
         }
     }
@@ -732,7 +816,10 @@
     ) {
         packageState.androidPackage?.requestedPermissions?.forEach { permissionName ->
             evaluatePermissionState(
-                packageState.appId, userId, permissionName, installedPackageState
+                packageState.appId,
+                userId,
+                permissionName,
+                installedPackageState
             )
         }
     }
@@ -779,57 +866,71 @@
             val wasGranted = oldFlags.hasBits(PermissionFlags.INSTALL_GRANTED)
             if (!wasGranted) {
                 val wasRevoked = oldFlags.hasBits(PermissionFlags.INSTALL_REVOKED)
-                val isRequestedByInstalledPackage = installedPackageState != null &&
-                    permissionName in installedPackageState.androidPackage!!.requestedPermissions
+                val isRequestedByInstalledPackage =
+                    installedPackageState != null &&
+                        permissionName in
+                            installedPackageState.androidPackage!!.requestedPermissions
                 val isRequestedBySystemPackage =
                     requestingPackageStates.anyIndexed { _, it -> it.isSystem }
-                val isCompatibilityPermission = requestingPackageStates.anyIndexed { _, it ->
-                    isCompatibilityPermissionForPackage(it.androidPackage!!, permissionName)
-                }
+                val isCompatibilityPermission =
+                    requestingPackageStates.anyIndexed { _, it ->
+                        isCompatibilityPermissionForPackage(it.androidPackage!!, permissionName)
+                    }
                 // If this is an existing, non-system package,
                 // then we can't add any new permissions to it.
                 // Except if this is a permission that was added to the platform
-                var newFlags = if (!wasRevoked || isRequestedByInstalledPackage ||
-                    isRequestedBySystemPackage || isCompatibilityPermission) {
-                    PermissionFlags.INSTALL_GRANTED
-                } else {
-                    PermissionFlags.INSTALL_REVOKED
-                }
+                var newFlags =
+                    if (
+                        !wasRevoked ||
+                            isRequestedByInstalledPackage ||
+                            isRequestedBySystemPackage ||
+                            isCompatibilityPermission
+                    ) {
+                        PermissionFlags.INSTALL_GRANTED
+                    } else {
+                        PermissionFlags.INSTALL_REVOKED
+                    }
                 if (permission.isAppOp) {
-                    newFlags = newFlags or (
-                        oldFlags and (PermissionFlags.ROLE or PermissionFlags.USER_SET)
-                    )
+                    newFlags =
+                        newFlags or
+                            (oldFlags and (PermissionFlags.ROLE or PermissionFlags.USER_SET))
                 }
                 setPermissionFlags(appId, userId, permissionName, newFlags)
             }
         } else if (permission.isSignature || permission.isInternal) {
             val wasProtectionGranted = oldFlags.hasBits(PermissionFlags.PROTECTION_GRANTED)
-            var newFlags = if (hasMissingPackage && wasProtectionGranted) {
-                // Keep the non-runtime permission grants for shared UID with missing androidPackage
-                PermissionFlags.PROTECTION_GRANTED
-            } else {
-                val mayGrantByPrivileged = !permission.isPrivileged ||
-                    requestingPackageStates.anyIndexed { _, it ->
-                        checkPrivilegedPermissionAllowlist(it, permission)
-                    }
-                val shouldGrantBySignature = permission.isSignature &&
-                    requestingPackageStates.anyIndexed { _, it ->
-                        shouldGrantPermissionBySignature(it, permission)
-                    }
-                val shouldGrantByProtectionFlags = requestingPackageStates.anyIndexed { _, it ->
-                    shouldGrantPermissionByProtectionFlags(it, permission)
-                }
-                if (mayGrantByPrivileged &&
-                    (shouldGrantBySignature || shouldGrantByProtectionFlags)) {
+            var newFlags =
+                if (hasMissingPackage && wasProtectionGranted) {
+                    // Keep the non-runtime permission grants for shared UID with missing
+                    // androidPackage
                     PermissionFlags.PROTECTION_GRANTED
                 } else {
-                    0
+                    val mayGrantByPrivileged =
+                        !permission.isPrivileged ||
+                            requestingPackageStates.anyIndexed { _, it ->
+                                checkPrivilegedPermissionAllowlist(it, permission)
+                            }
+                    val shouldGrantBySignature =
+                        permission.isSignature &&
+                            requestingPackageStates.anyIndexed { _, it ->
+                                shouldGrantPermissionBySignature(it, permission)
+                            }
+                    val shouldGrantByProtectionFlags =
+                        requestingPackageStates.anyIndexed { _, it ->
+                            shouldGrantPermissionByProtectionFlags(it, permission)
+                        }
+                    if (
+                        mayGrantByPrivileged &&
+                            (shouldGrantBySignature || shouldGrantByProtectionFlags)
+                    ) {
+                        PermissionFlags.PROTECTION_GRANTED
+                    } else {
+                        0
+                    }
                 }
-            }
             if (permission.isAppOp) {
-                newFlags = newFlags or (
-                    oldFlags and (PermissionFlags.ROLE or PermissionFlags.USER_SET)
-                )
+                newFlags =
+                    newFlags or (oldFlags and (PermissionFlags.ROLE or PermissionFlags.USER_SET))
             }
             // Different from the old implementation, which seemingly allows granting an
             // unallowlisted privileged permission via development or role but revokes it upon next
@@ -840,9 +941,9 @@
                 newFlags = newFlags or (oldFlags and PermissionFlags.RUNTIME_GRANTED)
             }
             if (permission.isRole) {
-                newFlags = newFlags or (
-                    oldFlags and (PermissionFlags.ROLE or PermissionFlags.RUNTIME_GRANTED)
-                )
+                newFlags =
+                    newFlags or
+                        (oldFlags and (PermissionFlags.ROLE or PermissionFlags.RUNTIME_GRANTED))
             }
             setPermissionFlags(appId, userId, permissionName, newFlags)
         } else if (permission.isRuntime) {
@@ -850,7 +951,9 @@
             val wasRevoked = newFlags != 0 && !PermissionFlags.isPermissionGranted(newFlags)
             val targetSdkVersion =
                 requestingPackageStates.reduceIndexed(Build.VERSION_CODES.CUR_DEVELOPMENT) {
-                    targetSdkVersion, _, packageState ->
+                    targetSdkVersion,
+                    _,
+                    packageState ->
                     targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
                 }
             if (targetSdkVersion < Build.VERSION_CODES.M) {
@@ -883,23 +986,27 @@
                     }
                 }
                 val wasGrantedByImplicit = newFlags.hasBits(PermissionFlags.IMPLICIT_GRANTED)
-                val isLeanbackNotificationsPermission = newState.externalState.isLeanback &&
-                    permissionName in NOTIFICATIONS_PERMISSIONS
-                val isImplicitPermission = requestingPackageStates.anyIndexed { _, it ->
-                    permissionName in it.androidPackage!!.implicitPermissions
-                }
-                val sourcePermissions = newState.externalState
-                    .implicitToSourcePermissions[permissionName]
-                val isAnySourcePermissionNonRuntime = sourcePermissions?.anyIndexed {
-                    _, sourcePermissionName ->
-                    val sourcePermission = newState.systemState.permissions[sourcePermissionName]
-                    checkNotNull(sourcePermission) {
-                        "Unknown source permission $sourcePermissionName in split permissions"
+                val isLeanbackNotificationsPermission =
+                    newState.externalState.isLeanback && permissionName in NOTIFICATIONS_PERMISSIONS
+                val isImplicitPermission =
+                    requestingPackageStates.anyIndexed { _, it ->
+                        permissionName in it.androidPackage!!.implicitPermissions
                     }
-                    !sourcePermission.isRuntime
-                } ?: false
-                val shouldGrantByImplicit = isLeanbackNotificationsPermission ||
-                    (isImplicitPermission && isAnySourcePermissionNonRuntime)
+                val sourcePermissions =
+                    newState.externalState.implicitToSourcePermissions[permissionName]
+                val isAnySourcePermissionNonRuntime =
+                    sourcePermissions?.anyIndexed { _, sourcePermissionName ->
+                        val sourcePermission =
+                            newState.systemState.permissions[sourcePermissionName]
+                        checkNotNull(sourcePermission) {
+                            "Unknown source permission $sourcePermissionName in split permissions"
+                        }
+                        !sourcePermission.isRuntime
+                    }
+                        ?: false
+                val shouldGrantByImplicit =
+                    isLeanbackNotificationsPermission ||
+                        (isImplicitPermission && isAnySourcePermissionNonRuntime)
                 if (shouldGrantByImplicit) {
                     newFlags = newFlags or PermissionFlags.IMPLICIT_GRANTED
                     if (wasRevoked) {
@@ -907,26 +1014,31 @@
                     }
                 } else {
                     newFlags = newFlags andInv PermissionFlags.IMPLICIT_GRANTED
-                    if ((wasGrantedByLegacy || wasGrantedByImplicit) &&
-                        newFlags.hasBits(PermissionFlags.APP_OP_REVOKED)) {
+                    if (
+                        (wasGrantedByLegacy || wasGrantedByImplicit) &&
+                            newFlags.hasBits(PermissionFlags.APP_OP_REVOKED)
+                    ) {
                         // The permission was granted from a compatibility grant or an implicit
                         // grant, however this flag might still be set if the user denied this
                         // permission in the settings. Hence upon app upgrade and when this
                         // permission is no longer LEGACY_GRANTED or IMPLICIT_GRANTED and we revoke
                         // the permission, we want to remove this flag so that the app can request
                         // the permission again.
-                        newFlags = newFlags andInv (
-                            PermissionFlags.RUNTIME_GRANTED or PermissionFlags.APP_OP_REVOKED
-                        )
+                        newFlags =
+                            newFlags andInv
+                                (PermissionFlags.RUNTIME_GRANTED or PermissionFlags.APP_OP_REVOKED)
                     }
                 }
                 if (!isImplicitPermission && hasImplicitFlag) {
                     newFlags = newFlags andInv PermissionFlags.IMPLICIT
                     var shouldRetainAsNearbyDevices = false
                     if (permissionName in NEARBY_DEVICES_PERMISSIONS) {
-                        val accessBackgroundLocationFlags = getPermissionFlags(
-                            appId, userId, Manifest.permission.ACCESS_BACKGROUND_LOCATION
-                        )
+                        val accessBackgroundLocationFlags =
+                            getPermissionFlags(
+                                appId,
+                                userId,
+                                Manifest.permission.ACCESS_BACKGROUND_LOCATION
+                            )
                         shouldRetainAsNearbyDevices =
                             PermissionFlags.isAppOpGranted(accessBackgroundLocationFlags) &&
                                 !accessBackgroundLocationFlags.hasBits(PermissionFlags.IMPLICIT)
@@ -937,46 +1049,57 @@
                             newFlags = newFlags or PermissionFlags.RUNTIME_GRANTED
                         }
                     } else {
-                        newFlags = newFlags andInv (
-                            PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET or
-                                PermissionFlags.USER_FIXED
-                        )
+                        newFlags =
+                            newFlags andInv
+                                (PermissionFlags.RUNTIME_GRANTED or
+                                    PermissionFlags.USER_SET or
+                                    PermissionFlags.USER_FIXED)
                     }
                 }
             }
 
             val wasExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
             val wasRestricted = newFlags.hasAnyBit(PermissionFlags.MASK_RESTRICTED)
-            val isExempt = if (permission.isHardOrSoftRestricted && !wasExempt && !wasRestricted) {
-                // All restricted permissions start as exempt. If there's an installer for the
-                // package, we will drop this UPGRADE_EXEMPT flag when we receive the
-                // onPackageInstalled() callback and set up the INSTALLER_EXEMPT flags.
-                // UPGRADE_EXEMPT is chosen instead of other flags because it is the same flag that
-                // was assigned to pre-installed apps in RuntimePermissionsUpgradeController, and to
-                // apps with missing permission state.
-                // This way we make sure both pre-installed apps, and apps updated/installed after
-                // a rollback snapshot is taken, can get the allowlist for permissions that won't be
-                // allowlisted otherwise.
-                newFlags = newFlags or PermissionFlags.UPGRADE_EXEMPT
-                true
-            } else {
-                wasExempt
-            }
-            newFlags = if (permission.isHardRestricted && !isExempt) {
-                newFlags or PermissionFlags.RESTRICTION_REVOKED
-            } else {
-                newFlags andInv PermissionFlags.RESTRICTION_REVOKED
-            }
-            newFlags = if (permission.isSoftRestricted && !isExempt) {
-                newFlags or PermissionFlags.SOFT_RESTRICTED
-            } else {
-                newFlags andInv PermissionFlags.SOFT_RESTRICTED
-            }
+            val isExempt =
+                if (permission.isHardOrSoftRestricted && !wasExempt && !wasRestricted) {
+                    // All restricted permissions start as exempt. If there's an installer for the
+                    // package, we will drop this UPGRADE_EXEMPT flag when we receive the
+                    // onPackageInstalled() callback and set up the INSTALLER_EXEMPT flags.
+                    // UPGRADE_EXEMPT is chosen instead of other flags because it is the same flag
+                    // that
+                    // was assigned to pre-installed apps in RuntimePermissionsUpgradeController,
+                    // and to
+                    // apps with missing permission state.
+                    // This way we make sure both pre-installed apps, and apps updated/installed
+                    // after
+                    // a rollback snapshot is taken, can get the allowlist for permissions that
+                    // won't be
+                    // allowlisted otherwise.
+                    newFlags = newFlags or PermissionFlags.UPGRADE_EXEMPT
+                    true
+                } else {
+                    wasExempt
+                }
+            newFlags =
+                if (permission.isHardRestricted && !isExempt) {
+                    newFlags or PermissionFlags.RESTRICTION_REVOKED
+                } else {
+                    newFlags andInv PermissionFlags.RESTRICTION_REVOKED
+                }
+            newFlags =
+                if (permission.isSoftRestricted && !isExempt) {
+                    newFlags or PermissionFlags.SOFT_RESTRICTED
+                } else {
+                    newFlags andInv PermissionFlags.SOFT_RESTRICTED
+                }
             setPermissionFlags(appId, userId, permissionName, newFlags)
         } else {
-            Slog.e(LOG_TAG, "Unknown protection level ${permission.protectionLevel}" +
-                "for permission ${permission.name} while evaluating permission state" +
-                "for appId $appId and userId $userId")
+            Slog.e(
+                LOG_TAG,
+                "Unknown protection level ${permission.protectionLevel}" +
+                    "for permission ${permission.name} while evaluating permission state" +
+                    "for appId $appId and userId $userId"
+            )
         }
     }
 
@@ -985,7 +1108,7 @@
         forEachPackageInAppId(appId) {
             implicitPermissions += it.androidPackage!!.implicitPermissions
         }
-        implicitPermissions.forEachIndexed implicitPermissions@ { _, implicitPermissionName ->
+        implicitPermissions.forEachIndexed implicitPermissions@{ _, implicitPermissionName ->
             val implicitPermission = newState.systemState.permissions[implicitPermissionName]
             checkNotNull(implicitPermission) {
                 "Unknown implicit permission $implicitPermissionName in split permissions"
@@ -999,10 +1122,11 @@
             if (!isNewPermission) {
                 return@implicitPermissions
             }
-            val sourcePermissions = newState.externalState
-                .implicitToSourcePermissions[implicitPermissionName] ?: return@implicitPermissions
+            val sourcePermissions =
+                newState.externalState.implicitToSourcePermissions[implicitPermissionName]
+                    ?: return@implicitPermissions
             var newFlags = getPermissionFlags(appId, userId, implicitPermissionName)
-            sourcePermissions.forEachIndexed sourcePermissions@ { _, sourcePermissionName ->
+            sourcePermissions.forEachIndexed sourcePermissions@{ _, sourcePermissionName ->
                 val sourcePermission = newState.systemState.permissions[sourcePermissionName]
                 checkNotNull(sourcePermission) {
                     "Unknown source permission $sourcePermissionName in split permissions"
@@ -1032,11 +1156,14 @@
         permissionName: String
     ): Boolean {
         for (compatibilityPermission in CompatibilityPermissionInfo.COMPAT_PERMS) {
-            if (compatibilityPermission.name == permissionName &&
-                androidPackage.targetSdkVersion < compatibilityPermission.sdkVersion) {
+            if (
+                compatibilityPermission.name == permissionName &&
+                    androidPackage.targetSdkVersion < compatibilityPermission.sdkVersion
+            ) {
                 Slog.i(
-                    LOG_TAG, "Auto-granting $permissionName to old package" +
-                    " ${androidPackage.packageName}"
+                    LOG_TAG,
+                    "Auto-granting $permissionName to old package" +
+                        " ${androidPackage.packageName}"
                 )
                 return true
             }
@@ -1058,15 +1185,23 @@
         //     and the defining package still trusts the old certificate for permissions
         // - or it shares the above relationships with the system package
         val packageSigningDetails = packageState.androidPackage!!.signingDetails
-        val sourceSigningDetails = newState.externalState
-            .packageStates[permission.packageName]?.androidPackage?.signingDetails
-        val platformSigningDetails = newState.externalState
-            .packageStates[PLATFORM_PACKAGE_NAME]!!.androidPackage!!.signingDetails
-        return sourceSigningDetails?.hasCommonSignerWithCapability(packageSigningDetails,
-            SigningDetails.CertCapabilities.PERMISSION) == true ||
+        val sourceSigningDetails =
+            newState.externalState.packageStates[permission.packageName]
+                ?.androidPackage
+                ?.signingDetails
+        val platformSigningDetails =
+            newState.externalState.packageStates[PLATFORM_PACKAGE_NAME]!!
+                .androidPackage!!
+                .signingDetails
+        return sourceSigningDetails?.hasCommonSignerWithCapability(
+            packageSigningDetails,
+            SigningDetails.CertCapabilities.PERMISSION
+        ) == true ||
             packageSigningDetails.hasAncestorOrSelf(platformSigningDetails) ||
-            platformSigningDetails.checkCapability(packageSigningDetails,
-                    SigningDetails.CertCapabilities.PERMISSION)
+            platformSigningDetails.checkCapability(
+                packageSigningDetails,
+                SigningDetails.CertCapabilities.PERMISSION
+            )
     }
 
     private fun MutateStateScope.checkPrivilegedPermissionAllowlist(
@@ -1082,8 +1217,9 @@
         if (!(packageState.isSystem && packageState.isPrivileged)) {
             return true
         }
-        if (permission.packageName !in
-            newState.externalState.privilegedPermissionAllowlistPackages) {
+        if (
+            permission.packageName !in newState.externalState.privilegedPermissionAllowlistPackages
+        ) {
             return true
         }
         val allowlistState = getPrivilegedPermissionAllowlistState(packageState, permission.name)
@@ -1099,13 +1235,15 @@
             // Apps that are in updated apex's do not need to be allowlisted
             if (!packageState.isApkInUpdatedApex) {
                 Slog.w(
-                    LOG_TAG, "Privileged permission ${permission.name} for package" +
-                    " ${packageState.packageName} (${packageState.path}) not in" +
-                    " privileged permission allowlist"
+                    LOG_TAG,
+                    "Privileged permission ${permission.name} for package" +
+                        " ${packageState.packageName} (${packageState.path}) not in" +
+                        " privileged permission allowlist"
                 )
                 if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
-                    privilegedPermissionAllowlistViolations += "${packageState.packageName}" +
-                        " (${packageState.path}): ${permission.name}"
+                    privilegedPermissionAllowlistViolations +=
+                        "${packageState.packageName}" +
+                            " (${packageState.path}): ${permission.name}"
                 }
             }
         }
@@ -1124,32 +1262,40 @@
         val apexModuleName = packageState.apexModuleName
         val packageName = packageState.packageName
         return when {
-            packageState.isVendor -> permissionAllowlist.getVendorPrivilegedAppAllowlistState(
-                packageName, permissionName
-            )
-            packageState.isProduct -> permissionAllowlist.getProductPrivilegedAppAllowlistState(
-                packageName, permissionName
-            )
+            packageState.isVendor ->
+                permissionAllowlist.getVendorPrivilegedAppAllowlistState(
+                    packageName,
+                    permissionName
+                )
+            packageState.isProduct ->
+                permissionAllowlist.getProductPrivilegedAppAllowlistState(
+                    packageName,
+                    permissionName
+                )
             packageState.isSystemExt ->
                 permissionAllowlist.getSystemExtPrivilegedAppAllowlistState(
-                    packageName, permissionName
+                    packageName,
+                    permissionName
                 )
             apexModuleName != null -> {
-                val nonApexAllowlistState = permissionAllowlist.getPrivilegedAppAllowlistState(
-                    packageName, permissionName
-                )
+                val nonApexAllowlistState =
+                    permissionAllowlist.getPrivilegedAppAllowlistState(packageName, permissionName)
                 if (nonApexAllowlistState != null) {
                     // TODO(andreionea): Remove check as soon as all apk-in-apex
                     // permission allowlists are migrated.
                     Slog.w(
-                        LOG_TAG, "Package $packageName is an APK in APEX but has permission" +
+                        LOG_TAG,
+                        "Package $packageName is an APK in APEX but has permission" +
                             " allowlist on the system image, please bundle the allowlist in the" +
                             " $apexModuleName APEX instead"
                     )
                 }
-                val apexAllowlistState = permissionAllowlist.getApexPrivilegedAppAllowlistState(
-                    apexModuleName, packageName, permissionName
-                )
+                val apexAllowlistState =
+                    permissionAllowlist.getApexPrivilegedAppAllowlistState(
+                        apexModuleName,
+                        packageName,
+                        permissionName
+                    )
                 apexAllowlistState ?: nonApexAllowlistState
             }
             else -> permissionAllowlist.getPrivilegedAppAllowlistState(packageName, permissionName)
@@ -1208,18 +1354,19 @@
         val knownPackages = newState.externalState.knownPackages
         val packageName = packageState.packageName
         if ((permission.isPrivileged || permission.isOem) && packageState.isSystem) {
-            val shouldGrant = if (packageState.isUpdatedSystemApp) {
-                // For updated system applications, a privileged/oem permission
-                // is granted only if it had been defined by the original application.
-                val disabledSystemPackageState = newState.externalState
-                    .disabledSystemPackageStates[packageState.packageName]
-                val disabledSystemPackage = disabledSystemPackageState?.androidPackage
-                disabledSystemPackage != null &&
-                    permission.name in disabledSystemPackage.requestedPermissions &&
-                    shouldGrantPrivilegedOrOemPermission(disabledSystemPackageState, permission)
-            } else {
-                shouldGrantPrivilegedOrOemPermission(packageState, permission)
-            }
+            val shouldGrant =
+                if (packageState.isUpdatedSystemApp) {
+                    // For updated system applications, a privileged/oem permission
+                    // is granted only if it had been defined by the original application.
+                    val disabledSystemPackageState =
+                        newState.externalState.disabledSystemPackageStates[packageState.packageName]
+                    val disabledSystemPackage = disabledSystemPackageState?.androidPackage
+                    disabledSystemPackage != null &&
+                        permission.name in disabledSystemPackage.requestedPermissions &&
+                        shouldGrantPrivilegedOrOemPermission(disabledSystemPackageState, permission)
+                } else {
+                    shouldGrantPrivilegedOrOemPermission(packageState, permission)
+                }
             if (shouldGrant) {
                 return true
             }
@@ -1230,16 +1377,18 @@
             // we still want to blindly grant it to old apps.
             return true
         }
-        if (permission.isInstaller && (
-            packageName in knownPackages[KnownPackages.PACKAGE_INSTALLER]!! ||
-                packageName in knownPackages[KnownPackages.PACKAGE_PERMISSION_CONTROLLER]!!
-        )) {
+        if (
+            permission.isInstaller &&
+                (packageName in knownPackages[KnownPackages.PACKAGE_INSTALLER]!! ||
+                    packageName in knownPackages[KnownPackages.PACKAGE_PERMISSION_CONTROLLER]!!)
+        ) {
             // If this permission is to be granted to the system installer and
             // this app is an installer or permission controller, then it gets the permission.
             return true
         }
-        if (permission.isVerifier &&
-            packageName in knownPackages[KnownPackages.PACKAGE_VERIFIER]!!) {
+        if (
+            permission.isVerifier && packageName in knownPackages[KnownPackages.PACKAGE_VERIFIER]!!
+        ) {
             // If this permission is to be granted to the system verifier and
             // this app is a verifier, then it gets the permission.
             return true
@@ -1248,53 +1397,67 @@
             // Any pre-installed system app is allowed to get this permission.
             return true
         }
-        if (permission.isKnownSigner &&
-            androidPackage.signingDetails.hasAncestorOrSelfWithDigest(permission.knownCerts)) {
+        if (
+            permission.isKnownSigner &&
+                androidPackage.signingDetails.hasAncestorOrSelfWithDigest(permission.knownCerts)
+        ) {
             // If the permission is to be granted to a known signer then check if any of this
             // app's signing certificates are in the trusted certificate digest Set.
             return true
         }
-        if (permission.isSetup &&
-            packageName in knownPackages[KnownPackages.PACKAGE_SETUP_WIZARD]!!) {
+        if (
+            permission.isSetup && packageName in knownPackages[KnownPackages.PACKAGE_SETUP_WIZARD]!!
+        ) {
             // If this permission is to be granted to the system setup wizard and
             // this app is a setup wizard, then it gets the permission.
             return true
         }
-        if (permission.isSystemTextClassifier &&
-            packageName in knownPackages[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER]!!) {
+        if (
+            permission.isSystemTextClassifier &&
+                packageName in knownPackages[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER]!!
+        ) {
             // Special permissions for the system default text classifier.
             return true
         }
-        if (permission.isConfigurator &&
-            packageName in knownPackages[KnownPackages.PACKAGE_CONFIGURATOR]!!) {
+        if (
+            permission.isConfigurator &&
+                packageName in knownPackages[KnownPackages.PACKAGE_CONFIGURATOR]!!
+        ) {
             // Special permissions for the device configurator.
             return true
         }
-        if (permission.isIncidentReportApprover &&
-            packageName in knownPackages[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER]!!) {
+        if (
+            permission.isIncidentReportApprover &&
+                packageName in knownPackages[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER]!!
+        ) {
             // If this permission is to be granted to the incident report approver and
             // this app is the incident report approver, then it gets the permission.
             return true
         }
-        if (permission.isAppPredictor &&
-            packageName in knownPackages[KnownPackages.PACKAGE_APP_PREDICTOR]!!) {
+        if (
+            permission.isAppPredictor &&
+                packageName in knownPackages[KnownPackages.PACKAGE_APP_PREDICTOR]!!
+        ) {
             // Special permissions for the system app predictor.
             return true
         }
-        if (permission.isCompanion &&
-            packageName in knownPackages[KnownPackages.PACKAGE_COMPANION]!!) {
+        if (
+            permission.isCompanion &&
+                packageName in knownPackages[KnownPackages.PACKAGE_COMPANION]!!
+        ) {
             // Special permissions for the system companion device manager.
             return true
         }
-        if (permission.isRetailDemo &&
-            packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO]!!) {
+        if (
+            permission.isRetailDemo &&
+                packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO]!!
+        ) {
             // Special permission granted only to the OEM specified retail demo app.
             // Note that the original code was passing app ID as UID, so this behavior is kept
             // unchanged.
             return true
         }
-        if (permission.isRecents &&
-            packageName in knownPackages[KnownPackages.PACKAGE_RECENTS]!!) {
+        if (permission.isRecents && packageName in knownPackages[KnownPackages.PACKAGE_RECENTS]!!) {
             // Special permission for the recents app.
             return true
         }
@@ -1319,9 +1482,10 @@
                     // flag.
                     if (packageState.isVendor && !permission.isVendorPrivileged) {
                         Slog.w(
-                            LOG_TAG, "Permission $permissionName cannot be granted to privileged" +
-                            " vendor app $packageName because it isn't a vendorPrivileged" +
-                            " permission"
+                            LOG_TAG,
+                            "Permission $permissionName cannot be granted to privileged" +
+                                " vendor app $packageName because it isn't a vendorPrivileged" +
+                                " permission"
                         )
                         return false
                     }
@@ -1330,8 +1494,11 @@
             }
             permission.isOem -> {
                 if (packageState.isOem) {
-                    val allowlistState = newState.externalState.permissionAllowlist
-                        .getOemAppAllowlistState(packageName, permissionName)
+                    val allowlistState =
+                        newState.externalState.permissionAllowlist.getOemAppAllowlistState(
+                            packageName,
+                            permissionName
+                        )
                     checkNotNull(allowlistState) {
                         "OEM permission $permissionName requested by package" +
                             " $packageName must be explicitly declared granted or not"
@@ -1358,13 +1525,18 @@
             val appId = externalState.packageStates[packageName]?.appId ?: continue
             newState.userStates.forEachIndexed { _, userId, _ ->
                 evaluatePermissionState(
-                    appId, userId, Manifest.permission.PACKAGE_USAGE_STATS, null
+                    appId,
+                    userId,
+                    Manifest.permission.PACKAGE_USAGE_STATS,
+                    null
                 )
             }
         }
         if (!privilegedPermissionAllowlistViolations.isEmpty()) {
-            throw IllegalStateException("Signature|privileged permissions not in privileged" +
-                " permission allowlist: $privilegedPermissionAllowlistViolations")
+            throw IllegalStateException(
+                "Signature|privileged permissions not in privileged" +
+                    " permission allowlist: $privilegedPermissionAllowlistViolations"
+            )
         }
     }
 
@@ -1389,10 +1561,14 @@
 
     fun GetStateScope.findPermissionTree(permissionName: String): Permission? =
         state.systemState.permissionTrees.firstNotNullOfOrNullIndexed {
-                _, permissionTreeName, permissionTree ->
-            if (permissionName.startsWith(permissionTreeName) &&
-                permissionName.length > permissionTreeName.length &&
-                permissionName[permissionTreeName.length] == '.') {
+            _,
+            permissionTreeName,
+            permissionTree ->
+            if (
+                permissionName.startsWith(permissionTreeName) &&
+                    permissionName.length > permissionTreeName.length &&
+                    permissionName[permissionTreeName.length] == '.'
+            ) {
                 permissionTree
             } else {
                 null
@@ -1403,15 +1579,11 @@
         newState.mutateSystemState().mutatePermissionTrees()[permission.name] = permission
     }
 
-    /**
-     * returns all permission group definitions available in the system
-     */
+    /** returns all permission group definitions available in the system */
     fun GetStateScope.getPermissionGroups(): IndexedMap<String, PermissionGroupInfo> =
         state.systemState.permissionGroups
 
-    /**
-     * returns all permission definitions available in the system
-     */
+    /** returns all permission definitions available in the system */
     fun GetStateScope.getPermissions(): IndexedMap<String, Permission> =
         state.systemState.permissions
 
@@ -1430,11 +1602,8 @@
     fun GetStateScope.getUidPermissionFlags(appId: Int, userId: Int): IndexedMap<String, Int>? =
         state.userStates[userId]?.appIdPermissionFlags?.get(appId)
 
-    fun GetStateScope.getPermissionFlags(
-        appId: Int,
-        userId: Int,
-        permissionName: String
-    ): Int = getPermissionFlags(state, appId, userId, permissionName)
+    fun GetStateScope.getPermissionFlags(appId: Int, userId: Int, permissionName: String): Int =
+        getPermissionFlags(state, appId, userId, permissionName)
 
     private fun MutateStateScope.getOldStatePermissionFlags(
         appId: Int,
@@ -1465,8 +1634,10 @@
         flagMask: Int,
         flagValues: Int
     ): Boolean {
-        val oldFlags = newState.userStates[userId]!!.appIdPermissionFlags[appId]
-            .getWithDefault(permissionName, 0)
+        val oldFlags =
+            newState.userStates[userId]!!
+                .appIdPermissionFlags[appId]
+                .getWithDefault(permissionName, 0)
         val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
         if (oldFlags == newFlags) {
             return false
@@ -1517,38 +1688,37 @@
         private const val PLATFORM_PACKAGE_NAME = "android"
 
         // A set of permissions that we don't want to revoke when they are no longer implicit.
-        private val RETAIN_IMPLICIT_FLAGS_PERMISSIONS = indexedSetOf(
-            Manifest.permission.ACCESS_MEDIA_LOCATION,
-            Manifest.permission.ACTIVITY_RECOGNITION,
-            Manifest.permission.READ_MEDIA_AUDIO,
-            Manifest.permission.READ_MEDIA_IMAGES,
-            Manifest.permission.READ_MEDIA_VIDEO,
-        )
+        private val RETAIN_IMPLICIT_FLAGS_PERMISSIONS =
+            indexedSetOf(
+                Manifest.permission.ACCESS_MEDIA_LOCATION,
+                Manifest.permission.ACTIVITY_RECOGNITION,
+                Manifest.permission.READ_MEDIA_AUDIO,
+                Manifest.permission.READ_MEDIA_IMAGES,
+                Manifest.permission.READ_MEDIA_VIDEO,
+            )
 
-        private val NEARBY_DEVICES_PERMISSIONS = indexedSetOf(
-            Manifest.permission.BLUETOOTH_ADVERTISE,
-            Manifest.permission.BLUETOOTH_CONNECT,
-            Manifest.permission.BLUETOOTH_SCAN,
-            Manifest.permission.NEARBY_WIFI_DEVICES
-        )
+        private val NEARBY_DEVICES_PERMISSIONS =
+            indexedSetOf(
+                Manifest.permission.BLUETOOTH_ADVERTISE,
+                Manifest.permission.BLUETOOTH_CONNECT,
+                Manifest.permission.BLUETOOTH_SCAN,
+                Manifest.permission.NEARBY_WIFI_DEVICES
+            )
 
-        private val NOTIFICATIONS_PERMISSIONS = indexedSetOf(
-            Manifest.permission.POST_NOTIFICATIONS
-        )
+        private val NOTIFICATIONS_PERMISSIONS = indexedSetOf(Manifest.permission.POST_NOTIFICATIONS)
 
-        private val STORAGE_AND_MEDIA_PERMISSIONS = indexedSetOf(
-            Manifest.permission.READ_EXTERNAL_STORAGE,
-            Manifest.permission.WRITE_EXTERNAL_STORAGE,
-            Manifest.permission.READ_MEDIA_AUDIO,
-            Manifest.permission.READ_MEDIA_VIDEO,
-            Manifest.permission.READ_MEDIA_IMAGES,
-            Manifest.permission.ACCESS_MEDIA_LOCATION,
-            Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
-        )
+        private val STORAGE_AND_MEDIA_PERMISSIONS =
+            indexedSetOf(
+                Manifest.permission.READ_EXTERNAL_STORAGE,
+                Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                Manifest.permission.READ_MEDIA_AUDIO,
+                Manifest.permission.READ_MEDIA_VIDEO,
+                Manifest.permission.READ_MEDIA_IMAGES,
+                Manifest.permission.ACCESS_MEDIA_LOCATION,
+                Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+            )
 
-        /**
-         * Mask for all permission flags that can be set by the user
-         */
+        /** Mask for all permission flags that can be set by the user */
         private const val USER_SETTABLE_MASK =
             PermissionFlags.USER_SET or
                 PermissionFlags.USER_FIXED or
@@ -1558,16 +1728,14 @@
                 PermissionFlags.USER_SELECTED
 
         /**
-         * Mask for all permission flags that imply we shouldn't automatically modify the
-         * permission grant state.
+         * Mask for all permission flags that imply we shouldn't automatically modify the permission
+         * grant state.
          */
         private const val SYSTEM_OR_POLICY_FIXED_MASK =
             PermissionFlags.SYSTEM_FIXED or PermissionFlags.POLICY_FIXED
     }
 
-    /**
-     * Listener for permission flags changes.
-     */
+    /** Listener for permission flags changes. */
     abstract class OnPermissionFlagsChangedListener {
         /**
          * Called when a permission flags change has been made to the upcoming new state.
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
index b644d8f..edacda0 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
@@ -32,7 +32,6 @@
      * Upgrade the package permissions, if needed.
      *
      * @param version package version
-     *
      * @see [com.android.server.permission.access.util.PackageVersionMigration.getVersion]
      */
     fun MutateStateScope.upgradePackageState(
@@ -43,7 +42,8 @@
         val packageName = packageState.packageName
         if (version <= 3) {
             Slog.v(
-                LOG_TAG, "Allowlisting and upgrading background location permission for " +
+                LOG_TAG,
+                "Allowlisting and upgrading background location permission for " +
                     "package: $packageName, version: $version, user:$userId"
             )
             allowlistRestrictedPermissions(packageState, userId)
@@ -51,7 +51,8 @@
         }
         if (version <= 10) {
             Slog.v(
-                LOG_TAG, "Upgrading access media location permission for package: $packageName" +
+                LOG_TAG,
+                "Upgrading access media location permission for package: $packageName" +
                     ", version: $version, user: $userId"
             )
             upgradeAccessMediaLocationPermission(packageState, userId)
@@ -59,7 +60,8 @@
         // TODO Enable isAtLeastT check, when moving subsystem to mainline.
         if (version <= 12 /*&& SdkLevel.isAtLeastT()*/) {
             Slog.v(
-                LOG_TAG, "Upgrading scoped permissions for package: $packageName" +
+                LOG_TAG,
+                "Upgrading scoped permissions for package: $packageName" +
                     ", version: $version, user: $userId"
             )
             upgradeAuralVisualMediaPermissions(packageState, userId)
@@ -67,7 +69,8 @@
         // TODO Enable isAtLeastU check, when moving subsystem to mainline.
         if (version <= 14 /*&& SdkLevel.isAtLeastU()*/) {
             Slog.v(
-                LOG_TAG, "Upgrading visual media permission for package: $packageName" +
+                LOG_TAG,
+                "Upgrading visual media permission for package: $packageName" +
                     ", version: $version, user: $userId"
             )
             upgradeUserSelectedVisualMediaPermission(packageState, userId)
@@ -84,8 +87,11 @@
             if (permissionName in LEGACY_RESTRICTED_PERMISSIONS) {
                 with(policy) {
                     updatePermissionFlags(
-                        packageState.appId, userId, permissionName,
-                        PermissionFlags.UPGRADE_EXEMPT, PermissionFlags.UPGRADE_EXEMPT
+                        packageState.appId,
+                        userId,
+                        permissionName,
+                        PermissionFlags.UPGRADE_EXEMPT,
+                        PermissionFlags.UPGRADE_EXEMPT
                     )
                 }
             }
@@ -96,21 +102,27 @@
         packageState: PackageState,
         userId: Int
     ) {
-        if (Manifest.permission.ACCESS_BACKGROUND_LOCATION in
-            packageState.androidPackage!!.requestedPermissions) {
+        if (
+            Manifest.permission.ACCESS_BACKGROUND_LOCATION in
+                packageState.androidPackage!!.requestedPermissions
+        ) {
             val appId = packageState.appId
-            val accessFineLocationFlags = with(policy) {
-                getPermissionFlags(appId, userId, Manifest.permission.ACCESS_FINE_LOCATION)
-            }
-            val accessCoarseLocationFlags = with(policy) {
-                getPermissionFlags(appId, userId, Manifest.permission.ACCESS_COARSE_LOCATION)
-            }
+            val accessFineLocationFlags =
+                with(policy) {
+                    getPermissionFlags(appId, userId, Manifest.permission.ACCESS_FINE_LOCATION)
+                }
+            val accessCoarseLocationFlags =
+                with(policy) {
+                    getPermissionFlags(appId, userId, Manifest.permission.ACCESS_COARSE_LOCATION)
+                }
             val isForegroundLocationGranted =
                 PermissionFlags.isAppOpGranted(accessFineLocationFlags) ||
                     PermissionFlags.isAppOpGranted(accessCoarseLocationFlags)
             if (isForegroundLocationGranted) {
                 grantRuntimePermission(
-                    packageState, userId, Manifest.permission.ACCESS_BACKGROUND_LOCATION
+                    packageState,
+                    userId,
+                    Manifest.permission.ACCESS_BACKGROUND_LOCATION
                 )
             }
         }
@@ -120,24 +132,29 @@
         packageState: PackageState,
         userId: Int
     ) {
-        if (Manifest.permission.ACCESS_MEDIA_LOCATION in
-            packageState.androidPackage!!.requestedPermissions) {
-            val flags = with(policy) {
-                getPermissionFlags(
-                    packageState.appId, userId, Manifest.permission.READ_EXTERNAL_STORAGE
-                )
-            }
+        if (
+            Manifest.permission.ACCESS_MEDIA_LOCATION in
+                packageState.androidPackage!!.requestedPermissions
+        ) {
+            val flags =
+                with(policy) {
+                    getPermissionFlags(
+                        packageState.appId,
+                        userId,
+                        Manifest.permission.READ_EXTERNAL_STORAGE
+                    )
+                }
             if (PermissionFlags.isAppOpGranted(flags)) {
                 grantRuntimePermission(
-                    packageState, userId, Manifest.permission.ACCESS_MEDIA_LOCATION
+                    packageState,
+                    userId,
+                    Manifest.permission.ACCESS_MEDIA_LOCATION
                 )
             }
         }
     }
 
-    /**
-     * Upgrade permissions based on storage permissions grant
-     */
+    /** Upgrade permissions based on storage permissions grant */
     private fun MutateStateScope.upgradeAuralVisualMediaPermissions(
         packageState: PackageState,
         userId: Int
@@ -147,15 +164,15 @@
             return
         }
         val requestedPermissionNames = androidPackage.requestedPermissions
-        val isStorageUserGranted = STORAGE_PERMISSIONS.anyIndexed { _, permissionName ->
-            if (permissionName !in requestedPermissionNames) {
-                return@anyIndexed false
+        val isStorageUserGranted =
+            STORAGE_PERMISSIONS.anyIndexed { _, permissionName ->
+                if (permissionName !in requestedPermissionNames) {
+                    return@anyIndexed false
+                }
+                val flags =
+                    with(policy) { getPermissionFlags(packageState.appId, userId, permissionName) }
+                PermissionFlags.isAppOpGranted(flags) && flags.hasBits(PermissionFlags.USER_SET)
             }
-            val flags = with(policy) {
-                getPermissionFlags(packageState.appId, userId, permissionName)
-            }
-            PermissionFlags.isAppOpGranted(flags) && flags.hasBits(PermissionFlags.USER_SET)
-        }
         if (isStorageUserGranted) {
             AURAL_VISUAL_MEDIA_PERMISSIONS.forEachIndexed { _, permissionName ->
                 if (permissionName in requestedPermissionNames) {
@@ -165,9 +182,7 @@
         }
     }
 
-    /**
-     * Upgrade permission based on the grant in [Manifest.permission_group.READ_MEDIA_VISUAL]
-     */
+    /** Upgrade permission based on the grant in [Manifest.permission_group.READ_MEDIA_VISUAL] */
     private fun MutateStateScope.upgradeUserSelectedVisualMediaPermission(
         packageState: PackageState,
         userId: Int
@@ -177,19 +192,21 @@
             return
         }
         val requestedPermissionNames = androidPackage.requestedPermissions
-        val isVisualMediaUserGranted = VISUAL_MEDIA_PERMISSIONS.anyIndexed { _, permissionName ->
-            if (permissionName !in requestedPermissionNames) {
-                return@anyIndexed false
+        val isVisualMediaUserGranted =
+            VISUAL_MEDIA_PERMISSIONS.anyIndexed { _, permissionName ->
+                if (permissionName !in requestedPermissionNames) {
+                    return@anyIndexed false
+                }
+                val flags =
+                    with(policy) { getPermissionFlags(packageState.appId, userId, permissionName) }
+                PermissionFlags.isAppOpGranted(flags) && flags.hasBits(PermissionFlags.USER_SET)
             }
-            val flags = with(policy) {
-                getPermissionFlags(packageState.appId, userId, permissionName)
-            }
-            PermissionFlags.isAppOpGranted(flags) && flags.hasBits(PermissionFlags.USER_SET)
-        }
         if (isVisualMediaUserGranted) {
             if (Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED in requestedPermissionNames) {
                 grantRuntimePermission(
-                    packageState, userId, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+                    packageState,
+                    userId,
+                    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
                 )
             }
         }
@@ -201,7 +218,8 @@
         permissionName: String
     ) {
         Slog.v(
-            LOG_TAG, "Granting runtime permission for package: ${packageState.packageName}, " +
+            LOG_TAG,
+            "Granting runtime permission for package: ${packageState.packageName}, " +
                 "permission: $permissionName, userId: $userId"
         )
         val permission = newState.systemState.permissions[permissionName]!!
@@ -220,13 +238,13 @@
         }
 
         flags = flags or PermissionFlags.RUNTIME_GRANTED
-        flags = flags andInv (
-            PermissionFlags.APP_OP_REVOKED or
-            PermissionFlags.IMPLICIT or
-            PermissionFlags.LEGACY_GRANTED or
-            PermissionFlags.HIBERNATION or
-            PermissionFlags.ONE_TIME
-        )
+        flags =
+            flags andInv
+                (PermissionFlags.APP_OP_REVOKED or
+                    PermissionFlags.IMPLICIT or
+                    PermissionFlags.LEGACY_GRANTED or
+                    PermissionFlags.HIBERNATION or
+                    PermissionFlags.ONE_TIME)
         with(policy) { setPermissionFlags(appId, userId, permissionName, flags) }
     }
 
@@ -234,39 +252,45 @@
         private val LOG_TAG = AppIdPermissionUpgrade::class.java.simpleName
 
         private const val MASK_ANY_FIXED =
-            PermissionFlags.USER_SET or PermissionFlags.USER_FIXED or
-            PermissionFlags.POLICY_FIXED or PermissionFlags.SYSTEM_FIXED
+            PermissionFlags.USER_SET or
+                PermissionFlags.USER_FIXED or
+                PermissionFlags.POLICY_FIXED or
+                PermissionFlags.SYSTEM_FIXED
 
-        private val LEGACY_RESTRICTED_PERMISSIONS = indexedSetOf(
-            Manifest.permission.ACCESS_BACKGROUND_LOCATION,
-            Manifest.permission.READ_EXTERNAL_STORAGE,
-            Manifest.permission.WRITE_EXTERNAL_STORAGE,
-            Manifest.permission.SEND_SMS,
-            Manifest.permission.RECEIVE_SMS,
-            Manifest.permission.RECEIVE_WAP_PUSH,
-            Manifest.permission.RECEIVE_MMS,
-            Manifest.permission.READ_CELL_BROADCASTS,
-            Manifest.permission.READ_CALL_LOG,
-            Manifest.permission.WRITE_CALL_LOG,
-            Manifest.permission.PROCESS_OUTGOING_CALLS
-        )
+        private val LEGACY_RESTRICTED_PERMISSIONS =
+            indexedSetOf(
+                Manifest.permission.ACCESS_BACKGROUND_LOCATION,
+                Manifest.permission.READ_EXTERNAL_STORAGE,
+                Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                Manifest.permission.SEND_SMS,
+                Manifest.permission.RECEIVE_SMS,
+                Manifest.permission.RECEIVE_WAP_PUSH,
+                Manifest.permission.RECEIVE_MMS,
+                Manifest.permission.READ_CELL_BROADCASTS,
+                Manifest.permission.READ_CALL_LOG,
+                Manifest.permission.WRITE_CALL_LOG,
+                Manifest.permission.PROCESS_OUTGOING_CALLS
+            )
 
-        private val STORAGE_PERMISSIONS = indexedSetOf(
-            Manifest.permission.READ_EXTERNAL_STORAGE,
-            Manifest.permission.WRITE_EXTERNAL_STORAGE
-        )
-        private val AURAL_VISUAL_MEDIA_PERMISSIONS = indexedSetOf(
-            Manifest.permission.READ_MEDIA_AUDIO,
-            Manifest.permission.READ_MEDIA_IMAGES,
-            Manifest.permission.READ_MEDIA_VIDEO,
-            Manifest.permission.ACCESS_MEDIA_LOCATION,
-            Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
-        )
+        private val STORAGE_PERMISSIONS =
+            indexedSetOf(
+                Manifest.permission.READ_EXTERNAL_STORAGE,
+                Manifest.permission.WRITE_EXTERNAL_STORAGE
+            )
+        private val AURAL_VISUAL_MEDIA_PERMISSIONS =
+            indexedSetOf(
+                Manifest.permission.READ_MEDIA_AUDIO,
+                Manifest.permission.READ_MEDIA_IMAGES,
+                Manifest.permission.READ_MEDIA_VIDEO,
+                Manifest.permission.ACCESS_MEDIA_LOCATION,
+                Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+            )
         // Visual media permissions in T
-        private val VISUAL_MEDIA_PERMISSIONS = indexedSetOf(
-            Manifest.permission.READ_MEDIA_IMAGES,
-            Manifest.permission.READ_MEDIA_VIDEO,
-            Manifest.permission.ACCESS_MEDIA_LOCATION
-        )
+        private val VISUAL_MEDIA_PERMISSIONS =
+            indexedSetOf(
+                Manifest.permission.READ_MEDIA_IMAGES,
+                Manifest.permission.READ_MEDIA_VIDEO,
+                Manifest.permission.ACCESS_MEDIA_LOCATION
+            )
     }
 }
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
index 37a4a90..1bee356 100644
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
@@ -135,9 +135,7 @@
     ) {
         tag(TAG_DEVICE) {
             attributeInterned(ATTR_ID, deviceId)
-            permissionFlags.forEachIndexed { _, name, flags ->
-                serializePermission(name, flags)
-            }
+            permissionFlags.forEachIndexed { _, name, flags -> serializePermission(name, flags) }
         }
     }
 
@@ -145,11 +143,12 @@
         tag(TAG_PERMISSION) {
             attributeInterned(ATTR_NAME, name)
             // Never serialize one-time permissions as granted.
-            val serializedFlags = if (flags.hasBits(PermissionFlags.ONE_TIME)) {
-                flags andInv PermissionFlags.RUNTIME_GRANTED
-            } else {
-                flags
-            }
+            val serializedFlags =
+                if (flags.hasBits(PermissionFlags.ONE_TIME)) {
+                    flags andInv PermissionFlags.RUNTIME_GRANTED
+                } else {
+                    flags
+                }
             attributeInt(ATTR_FLAGS, serializedFlags)
         }
     }
@@ -166,4 +165,4 @@
         private const val ATTR_NAME = "name"
         private const val ATTR_FLAGS = "flags"
     }
-}
\ No newline at end of file
+}
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..15a5859 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
@@ -53,8 +53,8 @@
     override fun MutateStateScope.onAppIdRemoved(appId: Int) {
         newState.userStates.forEachIndexed { userStateIndex, _, userState ->
             if (appId in userState.appIdDevicePermissionFlags) {
-                newState.mutateUserStateAt(userStateIndex)
-                    .mutateAppIdDevicePermissionFlags() -= appId
+                newState.mutateUserStateAt(userStateIndex).mutateAppIdDevicePermissionFlags() -=
+                    appId
             }
         }
     }
@@ -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
@@ -96,10 +96,11 @@
         val appId = packageState.appId
         val appIdPermissionFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags
         androidPackage.requestedPermissions.forEach { permissionName ->
-            val isRequestedByOtherPackages = anyPackageInAppId(appId) {
-                it.packageName != packageName &&
-                    permissionName in it.androidPackage!!.requestedPermissions
-            }
+            val isRequestedByOtherPackages =
+                anyPackageInAppId(appId) {
+                    it.packageName != packageName &&
+                        permissionName in it.androidPackage!!.requestedPermissions
+                }
             if (isRequestedByOtherPackages) {
                 return@forEach
             }
@@ -116,7 +117,9 @@
         }
         newState.userStates.forEachIndexed { _, userId, userState ->
             userState.appIdDevicePermissionFlags[appId]?.forEachReversedIndexed {
-                    _, deviceId, permissionFlags ->
+                _,
+                deviceId,
+                permissionFlags ->
                 permissionFlags.forEachReversedIndexed { _, permissionName, _ ->
                     if (permissionName !in requestedPermissions) {
                         setPermissionFlags(appId, deviceId, userId, permissionName, 0)
@@ -166,11 +169,17 @@
         userId: Int,
         permissionName: String
     ): Int {
-        val flags = state.userStates[userId]?.appIdDevicePermissionFlags?.get(appId)?.get(deviceId)
-                ?.getWithDefault(permissionName, 0) ?: 0
+        val flags =
+            state.userStates[userId]
+                ?.appIdDevicePermissionFlags
+                ?.get(appId)
+                ?.get(deviceId)
+                ?.getWithDefault(permissionName, 0)
+                ?: 0
         if (PermissionManager.DEBUG_DEVICE_PERMISSIONS) {
             Slog.i(
-                LOG_TAG, "getPermissionFlags: appId=$appId, userId=$userId," +
+                LOG_TAG,
+                "getPermissionFlags: appId=$appId, userId=$userId," +
                     " deviceId=$deviceId, permissionName=$permissionName," +
                     " flags=${PermissionFlags.toString(flags)}"
             )
@@ -186,7 +195,12 @@
         flags: Int
     ): Boolean =
         updatePermissionFlags(
-            appId, deviceId, userId, permissionName, PermissionFlags.MASK_ALL, flags
+            appId,
+            deviceId,
+            userId,
+            permissionName,
+            PermissionFlags.MASK_ALL,
+            flags
         )
 
     private fun MutateStateScope.updatePermissionFlags(
@@ -201,20 +215,23 @@
             Slog.w(LOG_TAG, "$permissionName is not a device aware permission.")
             return false
         }
-        val oldFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags[appId]
-            ?.get(deviceId).getWithDefault(permissionName, 0)
+        val oldFlags =
+            newState.userStates[userId]!!
+                .appIdDevicePermissionFlags[appId]
+                ?.get(deviceId)
+                .getWithDefault(permissionName, 0)
         val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
         if (oldFlags == newFlags) {
             return false
         }
         val appIdDevicePermissionFlags =
             newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags()
-        val devicePermissionFlags = appIdDevicePermissionFlags.mutateOrPut(appId) {
-            MutableIndexedReferenceMap()
-        }
+        val devicePermissionFlags =
+            appIdDevicePermissionFlags.mutateOrPut(appId) { MutableIndexedReferenceMap() }
         if (PermissionManager.DEBUG_DEVICE_PERMISSIONS) {
             Slog.i(
-                LOG_TAG, "setPermissionFlags(): appId=$appId, userId=$userId," +
+                LOG_TAG,
+                "setPermissionFlags(): appId=$appId, userId=$userId," +
                     " deviceId=$deviceId, permissionName=$permissionName," +
                     " newFlags=${PermissionFlags.toString(newFlags)}"
             )
@@ -229,40 +246,39 @@
         }
         listeners.forEachIndexed { _, it ->
             it.onDevicePermissionFlagsChanged(
-                appId, userId, deviceId, permissionName, oldFlags, newFlags
+                appId,
+                userId,
+                deviceId,
+                permissionName,
+                oldFlags,
+                newFlags
             )
         }
         return true
     }
 
     fun addOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
-        synchronized(listenersLock) {
-            listeners = listeners + listener
-        }
+        synchronized(listenersLock) { listeners = listeners + listener }
     }
 
     fun removeOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
-        synchronized(listenersLock) {
-            listeners = listeners - listener
-        }
+        synchronized(listenersLock) { listeners = listeners - listener }
     }
 
     private fun isDeviceAwarePermission(permissionName: String): Boolean =
-            DEVICE_AWARE_PERMISSIONS.contains(permissionName)
+        DEVICE_AWARE_PERMISSIONS.contains(permissionName)
 
     companion object {
         private val LOG_TAG = DevicePermissionPolicy::class.java.simpleName
 
-        /**
-         * These permissions are supported for virtual devices.
-         */
+        /** These permissions are supported for virtual devices. */
         // TODO: b/298661870 - Use new API to get the list of device aware permissions.
         val DEVICE_AWARE_PERMISSIONS = emptySet<String>()
     }
 
     /**
-     * TODO: b/289355341 - implement listener for permission changes
-     * Listener for permission flags changes.
+     * TODO: b/289355341 - implement listener for permission changes Listener for permission flags
+     *   changes.
      */
     abstract class OnDevicePermissionFlagsChangedListener {
         /**
@@ -288,4 +304,4 @@
          */
         abstract fun onStateMutated()
     }
-}
\ No newline at end of file
+}
diff --git a/services/permission/java/com/android/server/permission/access/permission/Permission.kt b/services/permission/java/com/android/server/permission/access/permission/Permission.kt
index c7fe1a9..aa56928 100644
--- a/services/permission/java/com/android/server/permission/access/permission/Permission.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/Permission.kt
@@ -26,8 +26,7 @@
     val isReconciled: Boolean,
     val type: Int,
     val appId: Int,
-    @Suppress("ArrayInDataClass")
-    val gids: IntArray = EmptyArray.INT,
+    @Suppress("ArrayInDataClass") val gids: IntArray = EmptyArray.INT,
     val areGidsPerUser: Boolean = false
 ) {
     inline val name: String
@@ -43,8 +42,7 @@
         get() = type == TYPE_DYNAMIC
 
     inline val protectionLevel: Int
-        @Suppress("DEPRECATION")
-        get() = permissionInfo.protectionLevel
+        @Suppress("DEPRECATION") get() = permissionInfo.protectionLevel
 
     inline val protection: Int
         get() = permissionInfo.protection
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
index 550d148..b9d89c2 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
@@ -32,15 +32,12 @@
  *
  * The old binary permission state is now tracked by multiple `*_GRANTED` and `*_REVOKED` flags, so
  * that:
- *
  * - With [INSTALL_GRANTED] and [INSTALL_REVOKED], we can now get rid of the old per-package
  *   `areInstallPermissionsFixed` attribute and correctly track it per-permission, finally fixing
  *   edge cases during module rollbacks.
- *
  * - With [LEGACY_GRANTED] and [IMPLICIT_GRANTED], we can now ensure that legacy permissions and
  *   implicit permissions split from non-runtime permissions are never revoked, without checking
  *   split permissions and package state everywhere slowly and in slightly different ways.
- *
  * - With [RESTRICTION_REVOKED], we can now get rid of the error-prone logic about revoking and
  *   potentially re-granting permissions upon restriction state changes.
  *
@@ -55,9 +52,7 @@
  * don't have any effect on the binary permission state.
  */
 object PermissionFlags {
-    /**
-     * Permission flag for a normal permission that is granted at package installation.
-     */
+    /** Permission flag for a normal permission that is granted at package installation. */
     const val INSTALL_GRANTED = 1 shl 0
 
     /**
@@ -97,8 +92,8 @@
     /**
      * Permission flag for a runtime permission whose state is set by the user.
      *
-     * For example, this flag may be set when the permission is allowed by the user in the
-     * request permission dialog, or managed in the permission settings.
+     * For example, this flag may be set when the permission is allowed by the user in the request
+     * permission dialog, or managed in the permission settings.
      *
      * @see PackageManager.FLAG_PERMISSION_USER_SET
      */
@@ -290,8 +285,8 @@
     /**
      * Permission flag for a runtime permission that is selected by the user.
      *
-     * For example, this flag may be set when one of the coarse/fine location accuracies is
-     * selected by the user.
+     * For example, this flag may be set when one of the coarse/fine location accuracies is selected
+     * by the user.
      *
      * This flag is informational and managed by PermissionController.
      *
@@ -299,28 +294,37 @@
      */
     const val USER_SELECTED = 1 shl 23
 
-    /**
-     * Mask for all permission flags.
-     */
+    /** Mask for all permission flags. */
     const val MASK_ALL = 0.inv()
 
-    /**
-     * Mask for all permission flags that may be applied to a runtime permission.
-     */
-    const val MASK_RUNTIME = ROLE or RUNTIME_GRANTED or USER_SET or USER_FIXED or POLICY_FIXED or
-        SYSTEM_FIXED or PREGRANT or LEGACY_GRANTED or IMPLICIT_GRANTED or IMPLICIT or
-        USER_SENSITIVE_WHEN_GRANTED or USER_SENSITIVE_WHEN_REVOKED or INSTALLER_EXEMPT or
-        SYSTEM_EXEMPT or UPGRADE_EXEMPT or RESTRICTION_REVOKED or SOFT_RESTRICTED or
-        APP_OP_REVOKED or ONE_TIME or HIBERNATION or USER_SELECTED
+    /** Mask for all permission flags that may be applied to a runtime permission. */
+    const val MASK_RUNTIME =
+        ROLE or
+            RUNTIME_GRANTED or
+            USER_SET or
+            USER_FIXED or
+            POLICY_FIXED or
+            SYSTEM_FIXED or
+            PREGRANT or
+            LEGACY_GRANTED or
+            IMPLICIT_GRANTED or
+            IMPLICIT or
+            USER_SENSITIVE_WHEN_GRANTED or
+            USER_SENSITIVE_WHEN_REVOKED or
+            INSTALLER_EXEMPT or
+            SYSTEM_EXEMPT or
+            UPGRADE_EXEMPT or
+            RESTRICTION_REVOKED or
+            SOFT_RESTRICTED or
+            APP_OP_REVOKED or
+            ONE_TIME or
+            HIBERNATION or
+            USER_SELECTED
 
-    /**
-     * Mask for all permission flags about permission exemption.
-     */
+    /** Mask for all permission flags about permission exemption. */
     const val MASK_EXEMPT = INSTALLER_EXEMPT or SYSTEM_EXEMPT or UPGRADE_EXEMPT
 
-    /**
-     * Mask for all permission flags about permission restriction.
-     */
+    /** Mask for all permission flags about permission restriction. */
     const val MASK_RESTRICTED = RESTRICTION_REVOKED or SOFT_RESTRICTED
 
     fun isPermissionGranted(flags: Int): Boolean {
@@ -363,11 +367,13 @@
             apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT
         }
         if (flags.hasBits(IMPLICIT)) {
-            apiFlags = apiFlags or if (flags.hasBits(LEGACY_GRANTED)) {
-                PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
-            } else {
-                PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
-            }
+            apiFlags =
+                apiFlags or
+                    if (flags.hasBits(LEGACY_GRANTED)) {
+                        PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
+                    } else {
+                        PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
+                    }
         }
         if (flags.hasBits(USER_SENSITIVE_WHEN_GRANTED)) {
             apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
@@ -440,8 +446,10 @@
         }
         flags = flags or (oldFlags and LEGACY_GRANTED)
         flags = flags or (oldFlags and IMPLICIT_GRANTED)
-        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) ||
-            apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)) {
+        if (
+            apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) ||
+                apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
+        ) {
             flags = flags or IMPLICIT
         }
         if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED)) {
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 bb24d51..ab3d78c 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,10 +41,10 @@
 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
+import android.permission.flags.Flags
 import android.provider.Settings
 import android.util.ArrayMap
 import android.util.ArraySet
@@ -88,28 +88,25 @@
 import com.android.server.pm.UserManagerService
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils
 import com.android.server.pm.permission.LegacyPermission
-import com.android.server.pm.permission.Permission as LegacyPermission2
 import com.android.server.pm.permission.LegacyPermissionSettings
 import com.android.server.pm.permission.LegacyPermissionState
+import com.android.server.pm.permission.Permission as LegacyPermission2
 import com.android.server.pm.permission.PermissionManagerServiceInterface
 import com.android.server.pm.permission.PermissionManagerServiceInternal
 import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageState
 import com.android.server.policy.SoftRestrictedPermissionPolicy
-import libcore.util.EmptyArray
 import java.io.FileDescriptor
 import java.io.PrintWriter
 import java.util.concurrent.CompletableFuture
 import java.util.concurrent.ExecutionException
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeoutException
+import libcore.util.EmptyArray
 
-/**
- * Modern implementation of [PermissionManagerServiceInterface].
- */
-class PermissionService(
-    private val service: AccessCheckingService
-) : PermissionManagerServiceInterface {
+/** Modern implementation of [PermissionManagerServiceInterface]. */
+class PermissionService(private val service: AccessCheckingService) :
+    PermissionManagerServiceInterface {
     private val policy =
         service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as AppIdPermissionPolicy
 
@@ -131,8 +128,7 @@
     private lateinit var onPermissionFlagsChangedListener: OnPermissionFlagsChangedListener
 
     private val storageVolumeLock = Any()
-    @GuardedBy("storageVolumeLock")
-    private val mountedStorageVolumes = ArraySet<String?>()
+    @GuardedBy("storageVolumeLock") private val mountedStorageVolumes = ArraySet<String?>()
     @GuardedBy("storageVolumeLock")
     private val storageVolumePackageNames = ArrayMap<String?, MutableList<String>>()
 
@@ -144,8 +140,8 @@
      * A permission backup might contain apps that are not installed. In this case we delay the
      * restoration until the app is installed.
      *
-     * This array (`userId -> noDelayedBackupLeft`) is `true` for all the users where
-     * there is **no more** delayed backup left.
+     * This array (`userId -> noDelayedBackupLeft`) is `true` for all the users where there is **no
+     * more** delayed backup left.
      */
     private val isDelayedPermissionBackupFinished = SparseBooleanArray()
 
@@ -154,9 +150,10 @@
         packageManagerInternal = LocalServices.getService(PackageManagerInternal::class.java)
         packageManagerLocal =
             LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
-        platformCompat = IPlatformCompat.Stub.asInterface(
-            ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)
-        )
+        platformCompat =
+            IPlatformCompat.Stub.asInterface(
+                ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)
+            )
         systemConfig = SystemConfig.getInstance()
         userManagerInternal = LocalServices.getService(UserManagerInternal::class.java)
         userManagerService = UserManagerService.getInstance()
@@ -166,8 +163,8 @@
         PackageManager.invalidatePackageInfoCache()
         PermissionManager.disablePackageNamePermissionCache()
 
-        handlerThread = ServiceThread(LOG_TAG, Process.THREAD_PRIORITY_BACKGROUND, true)
-            .apply { start() }
+        handlerThread =
+            ServiceThread(LOG_TAG, Process.THREAD_PRIORITY_BACKGROUND, true).apply { start() }
         handler = Handler(handlerThread.looper)
         onPermissionsChangeListeners = OnPermissionsChangeListeners(FgThread.get().looper)
         onPermissionFlagsChangedListener = OnPermissionFlagsChangedListener()
@@ -181,9 +178,7 @@
                 return emptyList()
             }
 
-            val permissionGroups = service.getState {
-                with(policy) { getPermissionGroups() }
-            }
+            val permissionGroups = service.getState { with(policy) { getPermissionGroups() } }
 
             return permissionGroups.mapNotNullIndexedTo(ArrayList()) { _, _, permissionGroup ->
                 if (snapshot.isPackageVisibleToUid(permissionGroup.packageName, callingUid)) {
@@ -206,9 +201,9 @@
                 return null
             }
 
-            permissionGroup = service.getState {
-                with(policy) { getPermissionGroups()[permissionGroupName] }
-            } ?: return null
+            permissionGroup =
+                service.getState { with(policy) { getPermissionGroups()[permissionGroupName] } }
+                    ?: return null
 
             if (!snapshot.isPackageVisibleToUid(permissionGroup.packageName, callingUid)) {
                 return null
@@ -242,29 +237,28 @@
                 return null
             }
 
-            permission = service.getState {
-                with(policy) { getPermissions()[permissionName] }
-            } ?: return null
+            permission =
+                service.getState { with(policy) { getPermissions()[permissionName] } }
+                    ?: return null
 
             if (!snapshot.isPackageVisibleToUid(permission.packageName, callingUid)) {
                 return null
             }
 
             val opPackage = snapshot.getPackageState(opPackageName)?.androidPackage
-            targetSdkVersion = when {
-                // System sees all flags.
-                isRootOrSystemOrShellUid(callingUid) -> Build.VERSION_CODES.CUR_DEVELOPMENT
-                opPackage != null -> opPackage.targetSdkVersion
-                else -> Build.VERSION_CODES.CUR_DEVELOPMENT
-            }
+            targetSdkVersion =
+                when {
+                    // System sees all flags.
+                    isRootOrSystemOrShellUid(callingUid) -> Build.VERSION_CODES.CUR_DEVELOPMENT
+                    opPackage != null -> opPackage.targetSdkVersion
+                    else -> Build.VERSION_CODES.CUR_DEVELOPMENT
+                }
         }
 
         return permission.generatePermissionInfo(flags, targetSdkVersion)
     }
 
-    /**
-     * Generate a new [PermissionInfo] from [Permission] and adjust it accordingly.
-     */
+    /** Generate a new [PermissionInfo] from [Permission] and adjust it accordingly. */
     private fun Permission.generatePermissionInfo(
         flags: Int,
         targetSdkVersion: Int = Build.VERSION_CODES.CUR_DEVELOPMENT
@@ -296,22 +290,27 @@
                 return null
             }
 
-            val permissions = service.getState {
-                if (permissionGroupName != null) {
-                    val permissionGroup =
-                        with(policy) { getPermissionGroups()[permissionGroupName] } ?: return null
+            val permissions =
+                service.getState {
+                    if (permissionGroupName != null) {
+                        val permissionGroup =
+                            with(policy) { getPermissionGroups()[permissionGroupName] }
+                                ?: return null
 
-                    if (!snapshot.isPackageVisibleToUid(permissionGroup.packageName, callingUid)) {
-                        return null
+                        if (
+                            !snapshot.isPackageVisibleToUid(permissionGroup.packageName, callingUid)
+                        ) {
+                            return null
+                        }
                     }
+
+                    with(policy) { getPermissions() }
                 }
 
-                with(policy) { getPermissions() }
-            }
-
             return permissions.mapNotNullIndexedTo(ArrayList()) { _, _, permission ->
-                if (permission.groupName == permissionGroupName &&
-                    snapshot.isPackageVisibleToUid(permission.packageName, callingUid)
+                if (
+                    permission.groupName == permissionGroupName &&
+                        snapshot.isPackageVisibleToUid(permission.packageName, callingUid)
                 ) {
                     permission.generatePermissionInfo(flags)
                 } else {
@@ -334,9 +333,7 @@
     private inline fun getPermissionsWithProtectionOrProtectionFlags(
         predicate: (Permission) -> Boolean
     ): List<PermissionInfo> {
-        val permissions = service.getState {
-            with(policy) { getPermissions() }
-        }
+        val permissions = service.getState { with(policy) { getPermissions() } }
 
         return permissions.mapNotNullIndexedTo(ArrayList()) { _, _, permission ->
             if (predicate(permission)) {
@@ -348,18 +345,16 @@
     }
 
     override fun getPermissionGids(permissionName: String, userId: Int): IntArray {
-        val permission = service.getState {
-            with(policy) { getPermissions()[permissionName] }
-        } ?: return EmptyArray.INT
+        val permission =
+            service.getState { with(policy) { getPermissions()[permissionName] } }
+                ?: return EmptyArray.INT
         return permission.getGidsForUser(userId)
     }
 
     override fun getInstalledPermissions(packageName: String): Set<String> {
         requireNotNull(packageName) { "packageName cannot be null" }
 
-        val permissions = service.getState {
-            with(policy) { getPermissions() }
-        }
+        val permissions = service.getState { with(policy) { getPermissions() } }
 
         return permissions.mapNotNullIndexedTo(ArraySet()) { _, _, permission ->
             if (permission.packageName == packageName) {
@@ -398,9 +393,8 @@
             permissionInfo.protectionLevel =
                 PermissionInfo.fixProtectionLevel(permissionInfo.protectionLevel)
 
-            val newPermission = Permission(
-                permissionInfo, true, Permission.TYPE_DYNAMIC, permissionTree.appId
-            )
+            val newPermission =
+                Permission(permissionInfo, true, Permission.TYPE_DYNAMIC, permissionTree.appId)
 
             with(policy) { addPermission(newPermission, !async) }
         }
@@ -431,7 +425,7 @@
         val callingUid = Binder.getCallingUid()
         val permissionTree = with(policy) { findPermissionTree(permissionName) }
         if (permissionTree != null && permissionTree.appId == UserHandle.getAppId(callingUid)) {
-                return permissionTree
+            return permissionTree
         }
 
         throw SecurityException(
@@ -447,8 +441,9 @@
         // if that plus the size of 'info' would exceed our stated maximum.
         if (permissionTree.appId != Process.SYSTEM_UID) {
             val permissionTreeFootprint = calculatePermissionTreeFootprint(permissionTree)
-            if (permissionTreeFootprint + permissionInfo.calculateFootprint() >
-                MAX_PERMISSION_TREE_FOOTPRINT
+            if (
+                permissionTreeFootprint + permissionInfo.calculateFootprint() >
+                    MAX_PERMISSION_TREE_FOOTPRINT
             ) {
                 throw SecurityException("Permission tree size cap exceeded")
             }
@@ -483,14 +478,16 @@
                 packageManagerInternal.getPackageStateInternal(androidPackage.packageName)
             if (packageState == null) {
                 Slog.e(
-                    LOG_TAG, "checkUidPermission: PackageState not found for AndroidPackage" +
+                    LOG_TAG,
+                    "checkUidPermission: PackageState not found for AndroidPackage" +
                         " $androidPackage"
                 )
                 return PackageManager.PERMISSION_DENIED
             }
-            val isPermissionGranted = service.getState {
-                isPermissionGranted(packageState, userId, permissionName, deviceId)
-            }
+            val isPermissionGranted =
+                service.getState {
+                    isPermissionGranted(packageState, userId, permissionName, deviceId)
+                }
             return if (isPermissionGranted) {
                 PackageManager.PERMISSION_GRANTED
             } else {
@@ -505,9 +502,7 @@
         }
     }
 
-    /**
-     * Internal implementation that should only be called by [checkUidPermission].
-     */
+    /** Internal implementation that should only be called by [checkUidPermission]. */
     private fun isSystemUidPermissionGranted(uid: Int, permissionName: String): Boolean {
         val uidPermissions = systemConfig.systemPermissions[uid] ?: return false
         if (permissionName in uidPermissions) {
@@ -532,12 +527,14 @@
             return PackageManager.PERMISSION_DENIED
         }
 
-        val packageState = packageManagerLocal.withFilteredSnapshot(Binder.getCallingUid(), userId)
-            .use { it.getPackageState(packageName) } ?: return PackageManager.PERMISSION_DENIED
+        val packageState =
+            packageManagerLocal.withFilteredSnapshot(Binder.getCallingUid(), userId).use {
+                it.getPackageState(packageName)
+            }
+                ?: return PackageManager.PERMISSION_DENIED
 
-        val isPermissionGranted = service.getState {
-            isPermissionGranted(packageState, userId, permissionName, deviceId)
-        }
+        val isPermissionGranted =
+            service.getState { isPermissionGranted(packageState, userId, permissionName, deviceId) }
         return if (isPermissionGranted) {
             PackageManager.PERMISSION_GRANTED
         } else {
@@ -566,8 +563,15 @@
         }
 
         val fullerPermissionName = FULLER_PERMISSIONS[permissionName]
-        if (fullerPermissionName != null &&
-            isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName, deviceId)
+        if (
+            fullerPermissionName != null &&
+                isSinglePermissionGranted(
+                    appId,
+                    userId,
+                    isInstantApp,
+                    fullerPermissionName,
+                    deviceId
+                )
         ) {
             return true
         }
@@ -575,9 +579,7 @@
         return false
     }
 
-    /**
-     * Internal implementation that should only be called by [isPermissionGranted].
-     */
+    /** Internal implementation that should only be called by [isPermissionGranted]. */
     private fun GetStateScope.isSinglePermissionGranted(
         appId: Int,
         userId: Int,
@@ -604,20 +606,27 @@
         requireNotNull(packageName) { "packageName cannot be null" }
         Preconditions.checkArgumentNonnegative(userId, "userId")
 
-        val packageState = packageManagerLocal.withUnfilteredSnapshot()
-            .use { it.getPackageState(packageName) }
+        val packageState =
+            packageManagerLocal.withUnfilteredSnapshot().use { it.getPackageState(packageName) }
         if (packageState == null) {
             Slog.w(LOG_TAG, "getGrantedPermissions: Unknown package $packageName")
             return emptySet()
         }
 
         service.getState {
-            val permissionFlags = with(policy) { getUidPermissionFlags(packageState.appId, userId) }
-                ?: return emptySet()
+            val permissionFlags =
+                with(policy) { getUidPermissionFlags(packageState.appId, userId) }
+                    ?: return emptySet()
 
             return permissionFlags.mapNotNullIndexedTo(ArraySet()) { _, permissionName, _ ->
-                if (isPermissionGranted(
-                        packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT)) {
+                if (
+                    isPermissionGranted(
+                        packageState,
+                        userId,
+                        permissionName,
+                        Context.DEVICE_ID_DEFAULT
+                    )
+                ) {
                     permissionName
                 } else {
                     null
@@ -635,8 +644,8 @@
             // permission state is not found, now we always return at least global GIDs. This is
             // more consistent with the pre-S-refactor behavior. This is also because we are now
             // actively trimming the per-UID objects when empty.
-            val permissionFlags = with(policy) { getUidPermissionFlags(appId, userId) }
-                ?: return globalGids.copyOf()
+            val permissionFlags =
+                with(policy) { getUidPermissionFlags(appId, userId) } ?: return globalGids.copyOf()
 
             val gids = GrowingIntArray.wrap(globalGids)
             permissionFlags.forEachIndexed { _, permissionName, flags ->
@@ -644,8 +653,8 @@
                     return@forEachIndexed
                 }
 
-                val permission = with(policy) { getPermissions()[permissionName] }
-                    ?: return@forEachIndexed
+                val permission =
+                    with(policy) { getPermissions()[permissionName] } ?: return@forEachIndexed
                 val permissionGids = permission.getGidsForUser(userId)
                 if (permissionGids.isEmpty()) {
                     return@forEachIndexed
@@ -662,9 +671,7 @@
         deviceId: Int,
         userId: Int
     ) {
-        setRuntimePermissionGranted(
-            packageName, userId, permissionName, deviceId, isGranted = true
-        )
+        setRuntimePermissionGranted(packageName, userId, permissionName, deviceId, isGranted = true)
     }
 
     override fun revokeRuntimePermission(
@@ -675,7 +682,12 @@
         reason: String?
     ) {
         setRuntimePermissionGranted(
-            packageName, userId, permissionName, deviceId, isGranted = false, revokeReason = reason
+            packageName,
+            userId,
+            permissionName,
+            deviceId,
+            isGranted = false,
+            revokeReason = reason
         )
     }
 
@@ -684,8 +696,12 @@
         userId: Int
     ) {
         setRuntimePermissionGranted(
-            packageName, userId, Manifest.permission.POST_NOTIFICATIONS, Context.DEVICE_ID_DEFAULT,
-            isGranted = false, skipKillUid = true
+            packageName,
+            userId,
+            Manifest.permission.POST_NOTIFICATIONS,
+            Context.DEVICE_ID_DEFAULT,
+            isGranted = false,
+            skipKillUid = true
         )
     }
 
@@ -704,19 +720,24 @@
     ) {
         val methodName = if (isGranted) "grantRuntimePermission" else "revokeRuntimePermission"
         val callingUid = Binder.getCallingUid()
-        val isDebugEnabled = if (isGranted) {
-            PermissionManager.DEBUG_TRACE_GRANTS
-        } else {
-            PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES
-        }
-        if (isDebugEnabled &&
-            PermissionManager.shouldTraceGrant(packageName, permissionName, userId)) {
+        val isDebugEnabled =
+            if (isGranted) {
+                PermissionManager.DEBUG_TRACE_GRANTS
+            } else {
+                PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES
+            }
+        if (
+            isDebugEnabled &&
+                PermissionManager.shouldTraceGrant(packageName, permissionName, userId)
+        ) {
             val callingUidName = packageManagerInternal.getNameForUid(callingUid)
             Slog.i(
-                LOG_TAG, "$methodName(packageName = $packageName," +
+                LOG_TAG,
+                "$methodName(packageName = $packageName," +
                     " permissionName = $permissionName" +
                     (if (isGranted) "" else "skipKillUid = $skipKillUid, reason = $revokeReason") +
-                    ", userId = $userId," + " callingUid = $callingUidName ($callingUid))",
+                    ", userId = $userId," +
+                    " callingUid = $callingUidName ($callingUid))",
                 RuntimeException()
             )
         }
@@ -727,23 +748,31 @@
         }
 
         enforceCallingOrSelfCrossUserPermission(
-            userId, enforceFullPermission = true, enforceShellRestriction = true, methodName
+            userId,
+            enforceFullPermission = true,
+            enforceShellRestriction = true,
+            methodName
         )
-        val enforcedPermissionName = if (isGranted) {
-            Manifest.permission.GRANT_RUNTIME_PERMISSIONS
-        } else {
-            Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
-        }
+        val enforcedPermissionName =
+            if (isGranted) {
+                Manifest.permission.GRANT_RUNTIME_PERMISSIONS
+            } else {
+                Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
+            }
         context.enforceCallingOrSelfPermission(enforcedPermissionName, methodName)
 
         val packageState: PackageState?
-        val permissionControllerPackageName = packageManagerInternal.getKnownPackageNames(
-            KnownPackages.PACKAGE_PERMISSION_CONTROLLER, UserHandle.USER_SYSTEM
-        ).first()
+        val permissionControllerPackageName =
+            packageManagerInternal
+                .getKnownPackageNames(
+                    KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
+                    UserHandle.USER_SYSTEM
+                )
+                .first()
         val permissionControllerPackageState: PackageState?
         packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
-            packageState = snapshot.filtered(callingUid, userId)
-                .use { it.getPackageState(packageName) }
+            packageState =
+                snapshot.filtered(callingUid, userId).use { it.getPackageState(packageName) }
             permissionControllerPackageState =
                 snapshot.getPackageState(permissionControllerPackageName)
         }
@@ -756,11 +785,13 @@
             return
         }
 
-        val canManageRolePermission = isRootOrSystemUid(callingUid) ||
-            UserHandle.getAppId(callingUid) == permissionControllerPackageState!!.appId
-        val overridePolicyFixed = context.checkCallingOrSelfPermission(
-            Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
-        ) == PackageManager.PERMISSION_GRANTED
+        val canManageRolePermission =
+            isRootOrSystemUid(callingUid) ||
+                UserHandle.getAppId(callingUid) == permissionControllerPackageState!!.appId
+        val overridePolicyFixed =
+            context.checkCallingOrSelfPermission(
+                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
+            ) == PackageManager.PERMISSION_GRANTED
 
         service.mutateState {
             with(onPermissionFlagsChangedListener) {
@@ -773,8 +804,15 @@
             }
 
             setRuntimePermissionGranted(
-                packageState, userId, permissionName, deviceId, isGranted, canManageRolePermission,
-                overridePolicyFixed, reportError = true, methodName
+                packageState,
+                userId,
+                permissionName,
+                deviceId,
+                isGranted,
+                canManageRolePermission,
+                overridePolicyFixed,
+                reportError = true,
+                methodName
             )
         }
     }
@@ -791,8 +829,9 @@
                     PackageInstaller.SessionParams.PERMISSION_STATE_DENIED -> {}
                     else -> {
                         Slog.w(
-                            LOG_TAG, "setRequestedPermissionStates: Unknown permission state" +
-                            " $permissionState for permission $permissionName"
+                            LOG_TAG,
+                            "setRequestedPermissionStates: Unknown permission state" +
+                                " $permissionState for permission $permissionName"
                         )
                         return@forEachIndexed
                     }
@@ -800,35 +839,50 @@
                 if (permissionName !in packageState.androidPackage!!.requestedPermissions) {
                     return@forEachIndexed
                 }
-                val permission = with(policy) { getPermissions()[permissionName] }
-                    ?: return@forEachIndexed
+                val permission =
+                    with(policy) { getPermissions()[permissionName] } ?: return@forEachIndexed
                 when {
                     permission.isDevelopment || permission.isRuntime -> {
-                        if (permissionState ==
-                            PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED) {
+                        if (
+                            permissionState ==
+                                PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
+                        ) {
                             setRuntimePermissionGranted(
-                                packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT,
-                                isGranted = true, canManageRolePermission = false,
-                                overridePolicyFixed = false, reportError = false,
+                                packageState,
+                                userId,
+                                permissionName,
+                                Context.DEVICE_ID_DEFAULT,
+                                isGranted = true,
+                                canManageRolePermission = false,
+                                overridePolicyFixed = false,
+                                reportError = false,
                                 "setRequestedPermissionStates"
                             )
                             updatePermissionFlags(
-                                packageState.appId, userId, permissionName,
+                                packageState.appId,
+                                userId,
+                                permissionName,
                                 Context.DEVICE_ID_DEFAULT,
                                 PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED or
-                                PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
+                                    PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
+                                0,
                                 canUpdateSystemFlags = false,
                                 reportErrorForUnknownPermission = false,
-                                isPermissionRequested = true, "setRequestedPermissionStates",
+                                isPermissionRequested = true,
+                                "setRequestedPermissionStates",
                                 packageState.packageName
                             )
                         }
                     }
-                    permission.isAppOp && permissionName in
+                    permission.isAppOp &&
+                        permissionName in
                             PackageInstallerService.INSTALLER_CHANGEABLE_APP_OP_PERMISSIONS ->
                         setAppOpPermissionGranted(
-                            packageState, userId, permissionName, permissionState ==
-                                    PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
+                            packageState,
+                            userId,
+                            permissionName,
+                            permissionState ==
+                                PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
                         )
                     else -> {}
                 }
@@ -836,9 +890,7 @@
         }
     }
 
-    /**
-     * Set whether a runtime permission is granted, without any validation on caller.
-     */
+    /** Set whether a runtime permission is granted, without any validation on caller. */
     private fun MutateStateScope.setRuntimePermissionGranted(
         packageState: PackageState,
         userId: Int,
@@ -876,8 +928,11 @@
                     // their permissions as always granted
                     return
                 }
-                if (isGranted && packageState.getUserStateOrDefault(userId).isInstantApp &&
-                    !permission.isInstant) {
+                if (
+                    isGranted &&
+                        packageState.getUserStateOrDefault(userId).isInstantApp &&
+                        !permission.isInstant
+                ) {
                     if (reportError) {
                         throw SecurityException(
                             "Cannot grant non-instant permission $permissionName to package" +
@@ -913,7 +968,8 @@
         if (oldFlags.hasBits(PermissionFlags.SYSTEM_FIXED)) {
             if (reportError) {
                 Slog.e(
-                    LOG_TAG, "$methodName: Cannot change system fixed permission $permissionName" +
+                    LOG_TAG,
+                    "$methodName: Cannot change system fixed permission $permissionName" +
                         " for package $packageName"
                 )
             }
@@ -923,7 +979,8 @@
         if (oldFlags.hasBits(PermissionFlags.POLICY_FIXED) && !overridePolicyFixed) {
             if (reportError) {
                 Slog.e(
-                    LOG_TAG, "$methodName: Cannot change policy fixed permission $permissionName" +
+                    LOG_TAG,
+                    "$methodName: Cannot change policy fixed permission $permissionName" +
                         " for package $packageName"
                 )
             }
@@ -933,7 +990,8 @@
         if (isGranted && oldFlags.hasBits(PermissionFlags.RESTRICTION_REVOKED)) {
             if (reportError) {
                 Slog.e(
-                    LOG_TAG, "$methodName: Cannot grant hard-restricted non-exempt permission" +
+                    LOG_TAG,
+                    "$methodName: Cannot grant hard-restricted non-exempt permission" +
                         " $permissionName to package $packageName"
                 )
             }
@@ -942,14 +1000,19 @@
 
         if (isGranted && oldFlags.hasBits(PermissionFlags.SOFT_RESTRICTED)) {
             // TODO: Refactor SoftRestrictedPermissionPolicy.
-            val softRestrictedPermissionPolicy = SoftRestrictedPermissionPolicy.forPermission(
-                context, AndroidPackageUtils.generateAppInfoWithoutState(androidPackage),
-                androidPackage, UserHandle.of(userId), permissionName
-            )
+            val softRestrictedPermissionPolicy =
+                SoftRestrictedPermissionPolicy.forPermission(
+                    context,
+                    AndroidPackageUtils.generateAppInfoWithoutState(androidPackage),
+                    androidPackage,
+                    UserHandle.of(userId),
+                    permissionName
+                )
             if (!softRestrictedPermissionPolicy.mayGrantPermission()) {
                 if (reportError) {
                     Slog.e(
-                        LOG_TAG, "$methodName: Cannot grant soft-restricted non-exempt permission" +
+                        LOG_TAG,
+                        "$methodName: Cannot grant soft-restricted non-exempt permission" +
                             " $permissionName to package $packageName"
                     )
                 }
@@ -965,15 +1028,17 @@
         setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
 
         if (permission.isRuntime) {
-            val action = if (isGranted) {
-                MetricsProto.MetricsEvent.ACTION_PERMISSION_GRANTED
-            } else {
-                MetricsProto.MetricsEvent.ACTION_PERMISSION_REVOKED
-            }
-            val log = LogMaker(action).apply {
-                setPackageName(packageName)
-                addTaggedData(MetricsProto.MetricsEvent.FIELD_PERMISSION, permissionName)
-            }
+            val action =
+                if (isGranted) {
+                    MetricsProto.MetricsEvent.ACTION_PERMISSION_GRANTED
+                } else {
+                    MetricsProto.MetricsEvent.ACTION_PERMISSION_REVOKED
+                }
+            val log =
+                LogMaker(action).apply {
+                    setPackageName(packageName)
+                    addTaggedData(MetricsProto.MetricsEvent.FIELD_PERMISSION, permissionName)
+                }
             metricsLogger.write(log)
         }
     }
@@ -984,8 +1049,8 @@
         permissionName: String,
         isGranted: Boolean
     ) {
-        val appOpPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as
-            AppIdAppOpPolicy
+        val appOpPolicy =
+            service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as AppIdAppOpPolicy
         val appOpName = AppOpsManager.permissionToOp(permissionName)!!
         val mode = if (isGranted) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
         with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
@@ -1003,17 +1068,20 @@
         }
 
         enforceCallingOrSelfCrossUserPermission(
-            userId, enforceFullPermission = true, enforceShellRestriction = false,
+            userId,
+            enforceFullPermission = true,
+            enforceShellRestriction = false,
             "getPermissionFlags"
         )
         enforceCallingOrSelfAnyPermission(
-            "getPermissionFlags", Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+            "getPermissionFlags",
+            Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
             Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
             Manifest.permission.GET_RUNTIME_PERMISSIONS
         )
 
-        val packageState = packageManagerLocal.withFilteredSnapshot()
-            .use { it.getPackageState(packageName) }
+        val packageState =
+            packageManagerLocal.withFilteredSnapshot().use { it.getPackageState(packageName) }
         if (packageState == null) {
             Slog.w(LOG_TAG, "getPermissionFlags: Unknown package $packageName")
             return 0
@@ -1045,12 +1113,17 @@
         }
 
         enforceCallingOrSelfCrossUserPermission(
-            userId, enforceFullPermission = true, enforceShellRestriction = false,
+            userId,
+            enforceFullPermission = true,
+            enforceShellRestriction = false,
             "isPermissionRevokedByPolicy"
         )
 
-        val packageState = packageManagerLocal.withFilteredSnapshot(Binder.getCallingUid(), userId)
-            .use { it.getPackageState(packageName) } ?: return false
+        val packageState =
+            packageManagerLocal.withFilteredSnapshot(Binder.getCallingUid(), userId).use {
+                it.getPackageState(packageName)
+            }
+                ?: return false
 
         service.getState {
             if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
@@ -1069,12 +1142,13 @@
         // TODO(b/173235285): Some caller may pass USER_ALL as userId.
         // Preconditions.checkArgumentNonnegative(userId, "userId")
 
-        val packageState = packageManagerLocal.withUnfilteredSnapshot()
-            .use { it.getPackageState(packageName) } ?: return false
+        val packageState =
+            packageManagerLocal.withUnfilteredSnapshot().use { it.getPackageState(packageName) }
+                ?: return false
 
-        val permissionFlags = service.getState {
-            with(policy) { getUidPermissionFlags(packageState.appId, userId) }
-        } ?: return false
+        val permissionFlags =
+            service.getState { with(policy) { getUidPermissionFlags(packageState.appId, userId) } }
+                ?: return false
         return permissionFlags.anyIndexed { _, _, it -> it.hasBits(REVIEW_REQUIRED_FLAGS) }
     }
 
@@ -1090,13 +1164,18 @@
         }
 
         enforceCallingOrSelfCrossUserPermission(
-            userId, enforceFullPermission = true, enforceShellRestriction = false,
+            userId,
+            enforceFullPermission = true,
+            enforceShellRestriction = false,
             "shouldShowRequestPermissionRationale"
         )
 
         val callingUid = Binder.getCallingUid()
-        val packageState = packageManagerLocal.withFilteredSnapshot(callingUid, userId)
-            .use { it.getPackageState(packageName) } ?: return false
+        val packageState =
+            packageManagerLocal.withFilteredSnapshot(callingUid, userId).use {
+                it.getPackageState(packageName)
+            }
+                ?: return false
         val appId = packageState.appId
         if (UserHandle.getAppId(callingUid) != appId) {
             return false
@@ -1115,17 +1194,24 @@
         }
 
         if (permissionName == Manifest.permission.ACCESS_BACKGROUND_LOCATION) {
-            val isBackgroundRationaleChangeEnabled = Binder::class.withClearedCallingIdentity {
-                try {
-                    platformCompat.isChangeEnabledByPackageName(
-                        BACKGROUND_RATIONALE_CHANGE_ID, packageName, userId
-                    )
-                } catch (e: RemoteException) {
-                    Slog.e(LOG_TAG, "shouldShowRequestPermissionRationale: Unable to check if" +
-                        " compatibility change is enabled", e)
-                    false
+            val isBackgroundRationaleChangeEnabled =
+                Binder::class.withClearedCallingIdentity {
+                    try {
+                        platformCompat.isChangeEnabledByPackageName(
+                            BACKGROUND_RATIONALE_CHANGE_ID,
+                            packageName,
+                            userId
+                        )
+                    } catch (e: RemoteException) {
+                        Slog.e(
+                            LOG_TAG,
+                            "shouldShowRequestPermissionRationale: Unable to check if" +
+                                " compatibility change is enabled",
+                            e
+                        )
+                        false
+                    }
                 }
-            }
             if (isBackgroundRationaleChangeEnabled) {
                 return true
             }
@@ -1144,20 +1230,30 @@
         userId: Int
     ) {
         val callingUid = Binder.getCallingUid()
-        if (PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES &&
-            PermissionManager.shouldTraceGrant(packageName, permissionName, userId)) {
-            val flagMaskString = DebugUtils.flagsToString(
-                PackageManager::class.java, "FLAG_PERMISSION_", flagMask.toLong()
-            )
-            val flagValuesString = DebugUtils.flagsToString(
-                PackageManager::class.java, "FLAG_PERMISSION_", flagValues.toLong()
-            )
+        if (
+            PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES &&
+                PermissionManager.shouldTraceGrant(packageName, permissionName, userId)
+        ) {
+            val flagMaskString =
+                DebugUtils.flagsToString(
+                    PackageManager::class.java,
+                    "FLAG_PERMISSION_",
+                    flagMask.toLong()
+                )
+            val flagValuesString =
+                DebugUtils.flagsToString(
+                    PackageManager::class.java,
+                    "FLAG_PERMISSION_",
+                    flagValues.toLong()
+                )
             val callingUidName = packageManagerInternal.getNameForUid(callingUid)
             Slog.i(
-                LOG_TAG, "updatePermissionFlags(packageName = $packageName," +
+                LOG_TAG,
+                "updatePermissionFlags(packageName = $packageName," +
                     " permissionName = $permissionName, flagMask = $flagMaskString," +
                     " flagValues = $flagValuesString, userId = $userId," +
-                    " callingUid = $callingUidName ($callingUid))", RuntimeException()
+                    " callingUid = $callingUidName ($callingUid))",
+                RuntimeException()
             )
         }
 
@@ -1167,11 +1263,14 @@
         }
 
         enforceCallingOrSelfCrossUserPermission(
-            userId, enforceFullPermission = true, enforceShellRestriction = true,
+            userId,
+            enforceFullPermission = true,
+            enforceShellRestriction = true,
             "updatePermissionFlags"
         )
         enforceCallingOrSelfAnyPermission(
-            "updatePermissionFlags", Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+            "updatePermissionFlags",
+            Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
             Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
         )
 
@@ -1208,8 +1307,10 @@
         // Different from the old implementation, which returns when package doesn't exist but
         // throws when package exists but isn't visible, we now return in both cases to avoid
         // leaking the package existence.
-        if (androidPackage == null ||
-            packageManagerInternal.filterAppAccess(packageName, callingUid, userId, false)) {
+        if (
+            androidPackage == null ||
+                packageManagerInternal.filterAppAccess(packageName, callingUid, userId, false)
+        ) {
             Slog.w(LOG_TAG, "updatePermissionFlags: Unknown package $packageName")
             return
         }
@@ -1219,26 +1320,35 @@
         // permissions.
         val canUpdateSystemFlags = isRootOrSystemUid(callingUid)
 
-        val isPermissionRequested = if (permissionName in androidPackage.requestedPermissions) {
-            // Fast path, the current package has requested the permission.
-            true
-        } else {
-            // Slow path, go through all shared user packages.
-            val sharedUserPackageNames =
-                packageManagerInternal.getSharedUserPackagesForPackage(packageName, userId)
-            sharedUserPackageNames.any { sharedUserPackageName ->
-                val sharedUserPackage = packageManagerInternal.getPackage(sharedUserPackageName)
-                sharedUserPackage != null &&
-                    permissionName in sharedUserPackage.requestedPermissions
+        val isPermissionRequested =
+            if (permissionName in androidPackage.requestedPermissions) {
+                // Fast path, the current package has requested the permission.
+                true
+            } else {
+                // Slow path, go through all shared user packages.
+                val sharedUserPackageNames =
+                    packageManagerInternal.getSharedUserPackagesForPackage(packageName, userId)
+                sharedUserPackageNames.any { sharedUserPackageName ->
+                    val sharedUserPackage = packageManagerInternal.getPackage(sharedUserPackageName)
+                    sharedUserPackage != null &&
+                        permissionName in sharedUserPackage.requestedPermissions
+                }
             }
-        }
 
         val appId = packageState.appId
         service.mutateState {
             updatePermissionFlags(
-                appId, userId, permissionName, deviceId, flagMask, flagValues, canUpdateSystemFlags,
-                reportErrorForUnknownPermission = true, isPermissionRequested,
-                "updatePermissionFlags", packageName
+                appId,
+                userId,
+                permissionName,
+                deviceId,
+                flagMask,
+                flagValues,
+                canUpdateSystemFlags,
+                reportErrorForUnknownPermission = true,
+                isPermissionRequested,
+                "updatePermissionFlags",
+                packageName
             )
         }
     }
@@ -1246,17 +1356,25 @@
     override fun updatePermissionFlagsForAllApps(flagMask: Int, flagValues: Int, userId: Int) {
         val callingUid = Binder.getCallingUid()
         if (PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES) {
-            val flagMaskString = DebugUtils.flagsToString(
-                PackageManager::class.java, "FLAG_PERMISSION_", flagMask.toLong()
-            )
-            val flagValuesString = DebugUtils.flagsToString(
-                PackageManager::class.java, "FLAG_PERMISSION_", flagValues.toLong()
-            )
+            val flagMaskString =
+                DebugUtils.flagsToString(
+                    PackageManager::class.java,
+                    "FLAG_PERMISSION_",
+                    flagMask.toLong()
+                )
+            val flagValuesString =
+                DebugUtils.flagsToString(
+                    PackageManager::class.java,
+                    "FLAG_PERMISSION_",
+                    flagValues.toLong()
+                )
             val callingUidName = packageManagerInternal.getNameForUid(callingUid)
             Slog.i(
-                LOG_TAG, "updatePermissionFlagsForAllApps(flagMask = $flagMaskString," +
+                LOG_TAG,
+                "updatePermissionFlagsForAllApps(flagMask = $flagMaskString," +
                     " flagValues = $flagValuesString, userId = $userId," +
-                    " callingUid = $callingUidName ($callingUid))", RuntimeException()
+                    " callingUid = $callingUidName ($callingUid))",
+                RuntimeException()
             )
         }
 
@@ -1266,11 +1384,14 @@
         }
 
         enforceCallingOrSelfCrossUserPermission(
-            userId, enforceFullPermission = true, enforceShellRestriction = true,
+            userId,
+            enforceFullPermission = true,
+            enforceShellRestriction = true,
             "updatePermissionFlagsForAllApps"
         )
         enforceCallingOrSelfAnyPermission(
-            "updatePermissionFlagsForAllApps", Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+            "updatePermissionFlagsForAllApps",
+            Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
             Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
         )
 
@@ -1278,26 +1399,30 @@
         // flag, we now properly sanitize all flags as in updatePermissionFlags().
         val canUpdateSystemFlags = isRootOrSystemUid(callingUid)
 
-        val packageStates = packageManagerLocal.withUnfilteredSnapshot()
-            .use { it.packageStates }
+        val packageStates = packageManagerLocal.withUnfilteredSnapshot().use { it.packageStates }
         service.mutateState {
             packageStates.forEach { (packageName, packageState) ->
                 val androidPackage = packageState.androidPackage ?: return@forEach
                 androidPackage.requestedPermissions.forEach { permissionName ->
                     updatePermissionFlags(
-                        packageState.appId, userId, permissionName, Context.DEVICE_ID_DEFAULT,
-                        flagMask, flagValues, canUpdateSystemFlags,
+                        packageState.appId,
+                        userId,
+                        permissionName,
+                        Context.DEVICE_ID_DEFAULT,
+                        flagMask,
+                        flagValues,
+                        canUpdateSystemFlags,
                         reportErrorForUnknownPermission = false,
-                        isPermissionRequested = true, "updatePermissionFlagsForAllApps", packageName
+                        isPermissionRequested = true,
+                        "updatePermissionFlagsForAllApps",
+                        packageName
                     )
                 }
             }
         }
     }
 
-    /**
-     * Update flags for a permission, without any validation on caller.
-     */
+    /** Update flags for a permission, without any validation on caller. */
     private fun MutateStateScope.updatePermissionFlags(
         appId: Int,
         userId: Int,
@@ -1311,20 +1436,19 @@
         methodName: String,
         packageName: String
     ) {
-        @Suppress("NAME_SHADOWING")
-        var flagMask = flagMask
-        @Suppress("NAME_SHADOWING")
-        var flagValues = flagValues
+        @Suppress("NAME_SHADOWING") var flagMask = flagMask
+        @Suppress("NAME_SHADOWING") var flagValues = flagValues
         // Only the system can change these flags and nothing else.
         if (!canUpdateSystemFlags) {
             // Different from the old implementation, which allowed non-system UIDs to remove (but
             // not add) permission restriction flags, we now consistently ignore them altogether.
-            val ignoredMask = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED or
-                PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT or
-                PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT or
-                PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT or
-                PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT or
-                PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION
+            val ignoredMask =
+                PackageManager.FLAG_PERMISSION_SYSTEM_FIXED or
+                    PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT or
+                    PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT or
+                    PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT or
+                    PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT or
+                    PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION
             flagMask = flagMask andInv ignoredMask
             flagValues = flagValues andInv ignoredMask
         }
@@ -1340,7 +1464,8 @@
         val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
         if (!isPermissionRequested && oldFlags == 0) {
             Slog.w(
-                LOG_TAG, "$methodName: Permission $permissionName isn't requested by package" +
+                LOG_TAG,
+                "$methodName: Permission $permissionName isn't requested by package" +
                     " $packageName"
             )
             return
@@ -1365,21 +1490,29 @@
         }
 
         enforceCallingOrSelfCrossUserPermission(
-            userId, enforceFullPermission = false, enforceShellRestriction = false,
+            userId,
+            enforceFullPermission = false,
+            enforceShellRestriction = false,
             "getAllowlistedRestrictedPermissions"
         )
 
         val callingUid = Binder.getCallingUid()
-        val packageState = packageManagerLocal.withFilteredSnapshot(callingUid, userId)
-            .use { it.getPackageState(packageName) } ?: return null
+        val packageState =
+            packageManagerLocal.withFilteredSnapshot(callingUid, userId).use {
+                it.getPackageState(packageName)
+            }
+                ?: return null
         val androidPackage = packageState.androidPackage ?: return null
 
-        val isCallerPrivileged = context.checkCallingOrSelfPermission(
-            Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS
-        ) == PackageManager.PERMISSION_GRANTED
+        val isCallerPrivileged =
+            context.checkCallingOrSelfPermission(
+                Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS
+            ) == PackageManager.PERMISSION_GRANTED
 
-        if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) &&
-            !isCallerPrivileged) {
+        if (
+            allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) &&
+                !isCallerPrivileged
+        ) {
             throw SecurityException(
                 "Querying system allowlist requires " +
                     Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS
@@ -1389,8 +1522,12 @@
         val isCallerInstallerOnRecord =
             packageManagerInternal.isCallerInstallerOfRecord(androidPackage, callingUid)
 
-        if (allowlistedFlags.hasAnyBit(PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE or
-                PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) {
+        if (
+            allowlistedFlags.hasAnyBit(
+                PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE or
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
+            )
+        ) {
             if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
                 throw SecurityException(
                     "Querying upgrade or installer allowlist requires being installer on record" +
@@ -1400,7 +1537,9 @@
         }
 
         return getAllowlistedRestrictedPermissionsUnchecked(
-            packageState.appId, allowlistedFlags, userId
+            packageState.appId,
+            allowlistedFlags,
+            userId
         )
     }
 
@@ -1414,8 +1553,11 @@
             with(policy) { getPermissionFlags(appId, userId, permissionName) }
         } else {
             if (permissionName !in DevicePermissionPolicy.DEVICE_AWARE_PERMISSIONS) {
-                Slog.i(LOG_TAG, "$permissionName is not device aware permission, " +
-                        " get the flags for default device.")
+                Slog.i(
+                    LOG_TAG,
+                    "$permissionName is not device aware permission, " +
+                        " get the flags for default device."
+                )
                 return with(policy) { getPermissionFlags(appId, userId, permissionName) }
             }
             val virtualDeviceManagerInternal = virtualDeviceManagerInternal
@@ -1423,8 +1565,7 @@
                 Slog.e(LOG_TAG, "Virtual device manager service is not available.")
                 return 0
             }
-            val persistentDeviceId =
-                    virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
+            val persistentDeviceId = virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
             if (persistentDeviceId != null) {
                 with(devicePolicy) {
                     getPermissionFlags(appId, persistentDeviceId, userId, permissionName)
@@ -1444,13 +1585,14 @@
         flags: Int
     ): Boolean {
         return if (!Flags.deviceAwarePermissionApis() || deviceId == Context.DEVICE_ID_DEFAULT) {
-            with(policy) {
-               setPermissionFlags(appId, userId, permissionName, flags)
-            }
+            with(policy) { setPermissionFlags(appId, userId, permissionName, flags) }
         } else {
             if (permissionName !in DevicePermissionPolicy.DEVICE_AWARE_PERMISSIONS) {
-                Slog.i(LOG_TAG, "$permissionName is not device aware permission, " +
-                        " set the flags for default device.")
+                Slog.i(
+                    LOG_TAG,
+                    "$permissionName is not device aware permission, " +
+                        " set the flags for default device."
+                )
                 return with(policy) { setPermissionFlags(appId, userId, permissionName, flags) }
             }
 
@@ -1459,8 +1601,7 @@
                 Slog.e(LOG_TAG, "Virtual device manager service is not available.")
                 return false
             }
-            val persistentDeviceId =
-                    virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
+            val persistentDeviceId = virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
             if (persistentDeviceId != null) {
                 with(devicePolicy) {
                     setPermissionFlags(appId, persistentDeviceId, userId, permissionName, flags)
@@ -1473,17 +1614,17 @@
     }
 
     /**
-     * This method does not enforce checks on the caller, should only be called after
-     * required checks.
+     * This method does not enforce checks on the caller, should only be called after required
+     * checks.
      */
     private fun getAllowlistedRestrictedPermissionsUnchecked(
         appId: Int,
         allowlistedFlags: Int,
         userId: Int
     ): ArrayList<String>? {
-        val permissionFlags = service.getState {
-            with(policy) { getUidPermissionFlags(appId, userId) }
-        } ?: return null
+        val permissionFlags =
+            service.getState { with(policy) { getUidPermissionFlags(appId, userId) } }
+                ?: return null
 
         var queryFlags = 0
         if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) {
@@ -1512,14 +1653,18 @@
             return false
         }
 
-        val permissionNames = getAllowlistedRestrictedPermissions(
-            packageName, allowlistedFlags, userId
-        ) ?: ArrayList(1)
+        val permissionNames =
+            getAllowlistedRestrictedPermissions(packageName, allowlistedFlags, userId)
+                ?: ArrayList(1)
 
         if (permissionName !in permissionNames) {
             permissionNames += permissionName
             return setAllowlistedRestrictedPermissions(
-                packageName, permissionNames, allowlistedFlags, userId, isAddingPermission = true
+                packageName,
+                permissionNames,
+                allowlistedFlags,
+                userId,
+                isAddingPermission = true
             )
         }
         return false
@@ -1531,14 +1676,22 @@
         permissionNames: List<String>,
         userId: Int
     ) {
-        val newPermissionNames = getAllowlistedRestrictedPermissionsUnchecked(appId,
-            PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER, userId
-        )?.let {
-            ArraySet(permissionNames).apply { this += it }.toList()
-        } ?: permissionNames
+        val newPermissionNames =
+            getAllowlistedRestrictedPermissionsUnchecked(
+                    appId,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER,
+                    userId
+                )
+                ?.let { ArraySet(permissionNames).apply { this += it }.toList() }
+                ?: permissionNames
 
-        setAllowlistedRestrictedPermissionsUnchecked(androidPackage, appId, newPermissionNames,
-            PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER, userId)
+        setAllowlistedRestrictedPermissionsUnchecked(
+            androidPackage,
+            appId,
+            newPermissionNames,
+            PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER,
+            userId
+        )
     }
 
     override fun removeAllowlistedRestrictedPermission(
@@ -1552,13 +1705,17 @@
             return false
         }
 
-        val permissions = getAllowlistedRestrictedPermissions(
-            packageName, allowlistedFlags, userId
-        ) ?: return false
+        val permissions =
+            getAllowlistedRestrictedPermissions(packageName, allowlistedFlags, userId)
+                ?: return false
 
         if (permissions.remove(permissionName)) {
             return setAllowlistedRestrictedPermissions(
-                packageName, permissions, allowlistedFlags, userId, isAddingPermission = false
+                packageName,
+                permissions,
+                allowlistedFlags,
+                userId,
+                isAddingPermission = false
             )
         }
 
@@ -1572,16 +1729,22 @@
             return false
         }
 
-        if (packageManagerLocal.withFilteredSnapshot()
-                .use { it.getPackageState(permission.packageName) } == null) {
+        if (
+            packageManagerLocal.withFilteredSnapshot().use {
+                it.getPackageState(permission.packageName)
+            } == null
+        ) {
             return false
         }
 
         val isImmutablyRestrictedPermission =
             permission.isHardOrSoftRestricted && permission.isImmutablyRestricted
-        if (isImmutablyRestrictedPermission && context.checkCallingOrSelfPermission(
-                Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS
-            ) != PackageManager.PERMISSION_GRANTED) {
+        if (
+            isImmutablyRestrictedPermission &&
+                context.checkCallingOrSelfPermission(
+                    Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS
+                ) != PackageManager.PERMISSION_GRANTED
+        ) {
             throw SecurityException(
                 "Cannot modify allowlist of an immutably restricted permission: ${permission.name}"
             )
@@ -1599,13 +1762,16 @@
     ): Boolean {
         Preconditions.checkArgument(allowlistedFlags.countOneBits() == 1)
 
-        val isCallerPrivileged = context.checkCallingOrSelfPermission(
-            Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS
-        ) == PackageManager.PERMISSION_GRANTED
+        val isCallerPrivileged =
+            context.checkCallingOrSelfPermission(
+                Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS
+            ) == PackageManager.PERMISSION_GRANTED
 
         val callingUid = Binder.getCallingUid()
-        val packageState = packageManagerLocal.withFilteredSnapshot(callingUid, userId)
-            .use { snapshot -> snapshot.packageStates[packageName] ?: return false }
+        val packageState =
+            packageManagerLocal.withFilteredSnapshot(callingUid, userId).use { snapshot ->
+                snapshot.packageStates[packageName] ?: return false
+            }
         val androidPackage = packageState.androidPackage ?: return false
 
         val isCallerInstallerOnRecord =
@@ -1627,15 +1793,19 @@
         }
 
         setAllowlistedRestrictedPermissionsUnchecked(
-            androidPackage, packageState.appId, permissionNames, allowlistedFlags, userId
+            androidPackage,
+            packageState.appId,
+            permissionNames,
+            allowlistedFlags,
+            userId
         )
 
         return true
     }
 
     /**
-     * This method does not enforce checks on the caller, should only be called after
-     * required checks.
+     * This method does not enforce checks on the caller, should only be called after required
+     * checks.
      */
     private fun setAllowlistedRestrictedPermissionsUnchecked(
         androidPackage: AndroidPackage,
@@ -1712,22 +1882,24 @@
                         }
                     }
 
-                    newFlags = if (permission.isHardRestricted && !isExempt) {
-                        newFlags or PermissionFlags.RESTRICTION_REVOKED
-                    } else {
-                        newFlags andInv PermissionFlags.RESTRICTION_REVOKED
-                    }
-                    newFlags = if (permission.isSoftRestricted && !isExempt) {
-                        newFlags or PermissionFlags.SOFT_RESTRICTED
-                    } else {
-                        newFlags andInv PermissionFlags.SOFT_RESTRICTED
-                    }
-                    mask = mask or PermissionFlags.RESTRICTION_REVOKED or
-                        PermissionFlags.SOFT_RESTRICTED
+                    newFlags =
+                        if (permission.isHardRestricted && !isExempt) {
+                            newFlags or PermissionFlags.RESTRICTION_REVOKED
+                        } else {
+                            newFlags andInv PermissionFlags.RESTRICTION_REVOKED
+                        }
+                    newFlags =
+                        if (permission.isSoftRestricted && !isExempt) {
+                            newFlags or PermissionFlags.SOFT_RESTRICTED
+                        } else {
+                            newFlags andInv PermissionFlags.SOFT_RESTRICTED
+                        }
+                    mask =
+                        mask or
+                            PermissionFlags.RESTRICTION_REVOKED or
+                            PermissionFlags.SOFT_RESTRICTED
 
-                    updatePermissionFlags(
-                        appId, userId, requestedPermission, mask, newFlags
-                    )
+                    updatePermissionFlags(appId, userId, requestedPermission, mask, newFlags)
                 }
             }
         }
@@ -1735,9 +1907,8 @@
 
     override fun resetRuntimePermissions(androidPackage: AndroidPackage, userId: Int) {
         service.mutateState {
-            with(policy) {
-                resetRuntimePermissions(androidPackage.packageName, userId)
-            }
+            with(policy) { resetRuntimePermissions(androidPackage.packageName, userId) }
+            with(devicePolicy) { resetRuntimePermissions(androidPackage.packageName, userId) }
         }
     }
 
@@ -1745,9 +1916,8 @@
         packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
             service.mutateState {
                 snapshot.packageStates.forEach { (_, packageState) ->
-                    with(policy) {
-                        resetRuntimePermissions(packageState.packageName, userId)
-                    }
+                    with(policy) { resetRuntimePermissions(packageState.packageName, userId) }
+                    with(devicePolicy) { resetRuntimePermissions(packageState.packageName, userId) }
                 }
             }
         }
@@ -1755,7 +1925,8 @@
 
     override fun addOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
         context.enforceCallingOrSelfPermission(
-            Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS, "addOnPermissionsChangeListener"
+            Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS,
+            "addOnPermissionsChangeListener"
         )
 
         onPermissionsChangeListeners.addListener(listener)
@@ -1780,9 +1951,7 @@
         requireNotNull(permissionName) { "permissionName cannot be null" }
         val packageNames = ArraySet<String>()
 
-        val permission = service.getState {
-            with(policy) { getPermissions()[permissionName] }
-        }
+        val permission = service.getState { with(policy) { getPermissions()[permissionName] } }
         if (permission == null || !permission.isAppOp) {
             packageNames.toTypedArray()
         }
@@ -1808,8 +1977,8 @@
                 androidPackage.requestedPermissions.forEach requestedPermissions@{ permissionName ->
                     val permission = permissions[permissionName] ?: return@requestedPermissions
                     if (permission.isAppOp) {
-                        val packageNames = appOpPermissionPackageNames
-                            .getOrPut(permissionName) { ArraySet() }
+                        val packageNames =
+                            appOpPermissionPackageNames.getOrPut(permissionName) { ArraySet() }
                         packageNames += androidPackage.packageName
                     }
                 }
@@ -1822,14 +1991,18 @@
         Preconditions.checkArgumentNonnegative(userId, "userId cannot be null")
         val backup = CompletableFuture<ByteArray>()
         permissionControllerManager.getRuntimePermissionBackup(
-            UserHandle.of(userId), PermissionThread.getExecutor(), backup::complete
+            UserHandle.of(userId),
+            PermissionThread.getExecutor(),
+            backup::complete
         )
 
         return try {
             backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
         } catch (e: Exception) {
             when (e) {
-                is TimeoutException, is InterruptedException, is ExecutionException -> {
+                is TimeoutException,
+                is InterruptedException,
+                is ExecutionException -> {
                     Slog.e(LOG_TAG, "Cannot create permission backup for user $userId", e)
                     null
                 }
@@ -1846,7 +2019,8 @@
             isDelayedPermissionBackupFinished -= userId
         }
         permissionControllerManager.stageAndApplyRuntimePermissionsBackup(
-            backup, UserHandle.of(userId)
+            backup,
+            UserHandle.of(userId)
         )
     }
 
@@ -1860,7 +2034,9 @@
             }
         }
         permissionControllerManager.applyStagedRuntimePermissionBackup(
-            packageName, UserHandle.of(userId), PermissionThread.getExecutor()
+            packageName,
+            UserHandle.of(userId),
+            PermissionThread.getExecutor()
         ) { hasMoreBackup ->
             if (hasMoreBackup) {
                 return@applyStagedRuntimePermissionBackup
@@ -1907,21 +2083,15 @@
     ): IndexedMap<Int, MutableIndexedSet<String>> {
         val appIds = MutableIndexedSet<Int>()
 
-        val packageStates = packageManagerLocal.withUnfilteredSnapshot().use {
-            it.packageStates
-        }
+        val packageStates = packageManagerLocal.withUnfilteredSnapshot().use { it.packageStates }
         state.userStates.forEachIndexed { _, _, userState ->
-            userState.appIdPermissionFlags.forEachIndexed { _, appId, _ ->
-                appIds.add(appId)
-            }
-            userState.appIdAppOpModes.forEachIndexed { _, appId, _ ->
-                appIds.add(appId)
-            }
-            userState.packageVersions.forEachIndexed packageVersions@ { _, packageName, _ ->
+            userState.appIdPermissionFlags.forEachIndexed { _, appId, _ -> appIds.add(appId) }
+            userState.appIdAppOpModes.forEachIndexed { _, appId, _ -> appIds.add(appId) }
+            userState.packageVersions.forEachIndexed packageVersions@{ _, packageName, _ ->
                 val appId = packageStates[packageName]?.appId ?: return@packageVersions
                 appIds.add(appId)
             }
-            userState.packageAppOpModes.forEachIndexed packageAppOpModes@ { _, packageName, _ ->
+            userState.packageAppOpModes.forEachIndexed packageAppOpModes@{ _, packageName, _ ->
                 val appId = packageStates[packageName]?.appId ?: return@packageAppOpModes
                 appIds.add(appId)
             }
@@ -1929,7 +2099,8 @@
 
         val appIdPackageNames = MutableIndexedMap<Int, MutableIndexedSet<String>>()
         packageStates.forEach { (_, packageState) ->
-            appIdPackageNames.getOrPut(packageState.appId) { MutableIndexedSet() }
+            appIdPackageNames
+                .getOrPut(packageState.appId) { MutableIndexedSet() }
                 .add(packageState.packageName)
         }
         // add non-package app IDs which might not be reported by package manager.
@@ -1960,10 +2131,7 @@
         println("Permission groups:")
         withIndent {
             state.systemState.permissionGroups.forEachIndexed { _, _, permissionGroup ->
-                println(
-                    "${permissionGroup.name}: " +
-                        "packageName=${permissionGroup.packageName}"
-                )
+                println("${permissionGroup.name}: " + "packageName=${permissionGroup.packageName}")
             }
         }
 
@@ -1992,7 +2160,9 @@
                     println("Permissions:")
                     withIndent {
                         userState.appIdPermissionFlags[appId]?.forEachIndexed {
-                            _, permissionName, flags ->
+                            _,
+                            permissionName,
+                            flags ->
                             val isGranted = PermissionFlags.isPermissionGranted(flags)
                             println(
                                 "$permissionName: granted=$isGranted, flags=" +
@@ -2002,7 +2172,9 @@
                     }
 
                     userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
-                            _, deviceId, devicePermissionFlags ->
+                        _,
+                        deviceId,
+                        devicePermissionFlags ->
                         println("Permissions (Device $deviceId):")
                         withIndent {
                             devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
@@ -2017,7 +2189,8 @@
 
                     println("App ops:")
                     withIndent {
-                        userState.appIdAppOpModes[appId]?.forEachIndexed {_, appOpName, appOpMode ->
+                        userState.appIdAppOpModes[appId]?.forEachIndexed { _, appOpName, appOpMode
+                            ->
                             println("$appOpName: mode=${AppOpsManager.modeToName(appOpMode)}")
                         }
                     }
@@ -2029,7 +2202,9 @@
                             println("App ops:")
                             withIndent {
                                 userState.packageAppOpModes[packageName]?.forEachIndexed {
-                                        _, appOpName, appOpMode ->
+                                    _,
+                                    appOpName,
+                                    appOpMode ->
                                     val modeName = AppOpsManager.modeToName(appOpMode)
                                     println("$appOpName: mode=$modeName")
                                 }
@@ -2048,24 +2223,30 @@
     }
 
     override fun getPermissionTEMP(permissionName: String): LegacyPermission2? {
-        val permission = service.getState {
-            with(policy) { getPermissions()[permissionName] }
-        } ?: return null
+        val permission =
+            service.getState { with(policy) { getPermissions()[permissionName] } } ?: return null
 
         return LegacyPermission2(
-            permission.permissionInfo, permission.type, permission.isReconciled, permission.appId,
-            permission.gids, permission.areGidsPerUser
+            permission.permissionInfo,
+            permission.type,
+            permission.isReconciled,
+            permission.appId,
+            permission.gids,
+            permission.areGidsPerUser
         )
     }
 
     override fun getLegacyPermissions(): List<LegacyPermission> =
-        service.getState {
-            with(policy) { getPermissions() }
-        }.mapIndexedTo(ArrayList()) { _, _, permission ->
-            LegacyPermission(
-                permission.permissionInfo, permission.type, permission.appId, permission.gids
-            )
-        }
+        service
+            .getState { with(policy) { getPermissions() } }
+            .mapIndexedTo(ArrayList()) { _, _, permission ->
+                LegacyPermission(
+                    permission.permissionInfo,
+                    permission.type,
+                    permission.appId,
+                    permission.gids
+                )
+            }
 
     override fun readLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
         // Package settings has been read when this method is called.
@@ -2086,9 +2267,7 @@
     ): List<LegacyPermission> =
         permissions.mapIndexedTo(ArrayList()) { _, _, permission ->
             // We don't need to provide UID and GIDs, which are only retrieved when dumping.
-            LegacyPermission(
-                permission.permissionInfo, permission.type, 0, EmptyArray.INT
-            )
+            LegacyPermission(permission.permissionInfo, permission.type, 0, EmptyArray.INT)
         }
 
     override fun getLegacyPermissionState(appId: Int): LegacyPermissionState {
@@ -2097,17 +2276,18 @@
         service.getState {
             val permissions = with(policy) { getPermissions() }
             userIds.forEachIndexed { _, userId ->
-                val permissionFlags = with(policy) { getUidPermissionFlags(appId, userId) }
-                    ?: return@forEachIndexed
+                val permissionFlags =
+                    with(policy) { getUidPermissionFlags(appId, userId) } ?: return@forEachIndexed
 
                 permissionFlags.forEachIndexed permissionFlags@{ _, permissionName, flags ->
                     val permission = permissions[permissionName] ?: return@permissionFlags
-                    val legacyPermissionState = LegacyPermissionState.PermissionState(
-                        permissionName,
-                        permission.isRuntime,
-                        PermissionFlags.isPermissionGranted(flags),
-                        PermissionFlags.toApiFlags(flags)
-                    )
+                    val legacyPermissionState =
+                        LegacyPermissionState.PermissionState(
+                            permissionName,
+                            permission.isRuntime,
+                            PermissionFlags.isPermissionGranted(flags),
+                            PermissionFlags.toApiFlags(flags)
+                        )
                     legacyState.putPermissionState(legacyPermissionState, userId)
                 }
             }
@@ -2131,16 +2311,13 @@
     override fun onSystemReady() {
         service.onSystemReady()
         virtualDeviceManagerInternal =
-                LocalServices.getService(VirtualDeviceManagerInternal::class.java)
-        permissionControllerManager = PermissionControllerManager(
-            context, PermissionThread.getHandler()
-        )
+            LocalServices.getService(VirtualDeviceManagerInternal::class.java)
+        permissionControllerManager =
+            PermissionControllerManager(context, PermissionThread.getHandler())
     }
 
     override fun onUserCreated(userId: Int) {
-        withCorkedPackageInfoCache {
-            service.onUserAdded(userId)
-        }
+        withCorkedPackageInfoCache { service.onUserAdded(userId) }
     }
 
     override fun onUserRemoved(userId: Int) {
@@ -2170,9 +2347,8 @@
             // of onPackageAdded() and reuse this order in onStorageVolumeAdded(). We need the
             // packages to be iterated in onStorageVolumeAdded() in the same order so that the
             // ownership of permissions is consistent.
-            storageVolumePackageNames.getOrPut(packageState.volumeUuid) {
-                mutableListOf()
-            } += packageState.packageName
+            storageVolumePackageNames.getOrPut(packageState.volumeUuid) { mutableListOf() } +=
+                packageState.packageName
             if (packageState.volumeUuid !in mountedStorageVolumes) {
                 // Wait for the storage volume to be mounted and batch the state mutation there.
                 return
@@ -2212,23 +2388,26 @@
                 return
             }
         }
-        val userIds = if (userId == UserHandle.USER_ALL) {
-            userManagerService.userIdsIncludingPreCreated
-        } else {
-            intArrayOf(userId)
-        }
+        val userIds =
+            if (userId == UserHandle.USER_ALL) {
+                userManagerService.userIdsIncludingPreCreated
+            } else {
+                intArrayOf(userId)
+            }
         @Suppress("NAME_SHADOWING")
-        userIds.forEach { userId ->
-            service.onPackageInstalled(androidPackage.packageName, userId)
-        }
+        userIds.forEach { userId -> service.onPackageInstalled(androidPackage.packageName, userId) }
 
         @Suppress("NAME_SHADOWING")
         userIds.forEach { userId ->
             // TODO: Remove when this callback receives packageState directly.
             val packageState =
                 packageManagerInternal.getPackageStateInternal(androidPackage.packageName)!!
-            addAllowlistedRestrictedPermissionsUnchecked(androidPackage, packageState.appId,
-                params.allowlistedRestrictedPermissions, userId)
+            addAllowlistedRestrictedPermissionsUnchecked(
+                androidPackage,
+                packageState.appId,
+                params.allowlistedRestrictedPermissions,
+                userId
+            )
             setRequestedPermissionStates(packageState, userId, params.permissionStates)
         }
     }
@@ -2241,11 +2420,12 @@
         sharedUserPkgs: List<AndroidPackage>,
         userId: Int
     ) {
-        val userIds = if (userId == UserHandle.USER_ALL) {
-            userManagerService.userIdsIncludingPreCreated
-        } else {
-            intArrayOf(userId)
-        }
+        val userIds =
+            if (userId == UserHandle.USER_ALL) {
+                userManagerService.userIdsIncludingPreCreated
+            } else {
+                intArrayOf(userId)
+            }
         userIds.forEach { service.onPackageUninstalled(packageName, appId, it) }
         val packageState = packageManagerInternal.packageStates[packageName]
         if (packageState == null) {
@@ -2262,31 +2442,26 @@
         }
     }
 
-    /**
-     * Check whether a UID is root or system UID.
-     */
+    /** Check whether a UID is root or system UID. */
     private fun isRootOrSystemUid(uid: Int) =
         when (UserHandle.getAppId(uid)) {
-            Process.ROOT_UID, Process.SYSTEM_UID -> true
+            Process.ROOT_UID,
+            Process.SYSTEM_UID -> true
             else -> false
         }
 
-    /**
-     * Check whether a UID is shell UID.
-     */
+    /** Check whether a UID is shell UID. */
     private fun isShellUid(uid: Int) = UserHandle.getAppId(uid) == Process.SHELL_UID
 
-    /**
-     * Check whether a UID is root, system or shell UID.
-     */
+    /** Check whether a UID is root, system or shell UID. */
     private fun isRootOrSystemOrShellUid(uid: Int) = isRootOrSystemUid(uid) || isShellUid(uid)
 
     /**
      * This method should typically only be used when granting or revoking permissions, since the
      * app may immediately restart after this call.
      *
-     * If you're doing surgery on app code/data, use [PackageFreezer] to guard your work against
-     * the app being relaunched.
+     * If you're doing surgery on app code/data, use [PackageFreezer] to guard your work against the
+     * app being relaunched.
      */
     private fun killUid(uid: Int, reason: String) {
         val activityManager = ActivityManager.getService()
@@ -2303,9 +2478,7 @@
         }
     }
 
-    /**
-     * @see PackageManagerLocal.withFilteredSnapshot
-     */
+    /** @see PackageManagerLocal.withFilteredSnapshot */
     private fun PackageManagerLocal.withFilteredSnapshot(
         callingUid: Int,
         userId: Int
@@ -2323,35 +2496,27 @@
         packageName: String
     ): PackageState? = packageStates[packageName]
 
-    /**
-     * Check whether a UID belongs to an instant app.
-     */
+    /** Check whether a UID belongs to an instant app. */
     private fun PackageManagerLocal.UnfilteredSnapshot.isUidInstantApp(uid: Int): Boolean =
         // Unfortunately we don't have the API for getting the owner UID of an isolated UID or the
         // API for getting the SharedUserApi object for an app ID yet, so for now we just keep
         // calling the old API.
         packageManagerInternal.getInstantAppPackageName(uid) != null
 
-    /**
-     * Check whether a package is visible to a UID within the same user as the UID.
-     */
+    /** Check whether a package is visible to a UID within the same user as the UID. */
     private fun PackageManagerLocal.UnfilteredSnapshot.isPackageVisibleToUid(
         packageName: String,
         uid: Int
     ): Boolean = isPackageVisibleToUid(packageName, UserHandle.getUserId(uid), uid)
 
-    /**
-     * Check whether a package in a particular user is visible to a UID.
-     */
+    /** Check whether a package in a particular user is visible to a UID. */
     private fun PackageManagerLocal.UnfilteredSnapshot.isPackageVisibleToUid(
         packageName: String,
         userId: Int,
         uid: Int
     ): Boolean = filtered(uid, userId).use { it.getPackageState(packageName) != null }
 
-    /**
-     * @see PackageManagerLocal.UnfilteredSnapshot.filtered
-     */
+    /** @see PackageManagerLocal.UnfilteredSnapshot.filtered */
     private fun PackageManagerLocal.UnfilteredSnapshot.filtered(
         callingUid: Int,
         userId: Int
@@ -2374,13 +2539,16 @@
         val callingUid = Binder.getCallingUid()
         val callingUserId = UserHandle.getUserId(callingUid)
         if (userId != callingUserId) {
-            val permissionName = if (enforceFullPermission) {
-                Manifest.permission.INTERACT_ACROSS_USERS_FULL
-            } else {
-                Manifest.permission.INTERACT_ACROSS_USERS
-            }
-            if (context.checkCallingOrSelfPermission(permissionName) !=
-                PackageManager.PERMISSION_GRANTED) {
+            val permissionName =
+                if (enforceFullPermission) {
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL
+                } else {
+                    Manifest.permission.INTERACT_ACROSS_USERS
+                }
+            if (
+                context.checkCallingOrSelfPermission(permissionName) !=
+                    PackageManager.PERMISSION_GRANTED
+            ) {
                 val exceptionMessage = buildString {
                     if (message != null) {
                         append(message)
@@ -2397,9 +2565,11 @@
             }
         }
         if (enforceShellRestriction && isShellUid(callingUid)) {
-            val isShellRestricted = userManagerInternal.hasUserRestriction(
-                UserManager.DISALLOW_DEBUGGING_FEATURES, userId
-            )
+            val isShellRestricted =
+                userManagerInternal.hasUserRestriction(
+                    UserManager.DISALLOW_DEBUGGING_FEATURES,
+                    userId
+                )
             if (isShellRestricted) {
                 val exceptionMessage = buildString {
                     if (message != null) {
@@ -2424,10 +2594,11 @@
         message: String?,
         vararg permissionNames: String
     ) {
-        val hasAnyPermission = permissionNames.any { permissionName ->
-            context.checkCallingOrSelfPermission(permissionName) ==
-                PackageManager.PERMISSION_GRANTED
-        }
+        val hasAnyPermission =
+            permissionNames.any { permissionName ->
+                context.checkCallingOrSelfPermission(permissionName) ==
+                    PackageManager.PERMISSION_GRANTED
+            }
         if (!hasAnyPermission) {
             val exceptionMessage = buildString {
                 if (message != null) {
@@ -2443,9 +2614,7 @@
         }
     }
 
-    /**
-     * Callback invoked when interesting actions have been taken on a permission.
-     */
+    /** Callback invoked when interesting actions have been taken on a permission. */
     private inner class OnPermissionFlagsChangedListener :
         AppIdPermissionPolicy.OnPermissionFlagsChangedListener() {
         private var isPermissionFlagsChanged = false
@@ -2476,9 +2645,8 @@
             isPermissionFlagsChanged = true
 
             val uid = UserHandle.getUid(userId, appId)
-            val permission = service.getState {
-                with(policy) { getPermissions()[permissionName] }
-            } ?: return
+            val permission =
+                service.getState { with(policy) { getPermissions()[permissionName] } } ?: return
             val wasPermissionGranted = PermissionFlags.isPermissionGranted(oldFlags)
             val isPermissionGranted = PermissionFlags.isPermissionGranted(newFlags)
 
@@ -2512,16 +2680,20 @@
             runtimePermissionChangedUids.clear()
 
             if (!isKillRuntimePermissionRevokedUidsSkipped) {
-                val reason = if (killRuntimePermissionRevokedUidsReasons.isNotEmpty()) {
-                    killRuntimePermissionRevokedUidsReasons.joinToString(", ")
-                } else {
-                    PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED
-                }
+                val reason =
+                    if (killRuntimePermissionRevokedUidsReasons.isNotEmpty()) {
+                        killRuntimePermissionRevokedUidsReasons.joinToString(", ")
+                    } else {
+                        PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED
+                    }
                 runtimePermissionRevokedUids.forEachIndexed {
-                    _, uid, areOnlyNotificationsPermissionsRevoked ->
+                    _,
+                    uid,
+                    areOnlyNotificationsPermissionsRevoked ->
                     handler.post {
-                        if (areOnlyNotificationsPermissionsRevoked &&
-                            isAppBackupAndRestoreRunning(uid)
+                        if (
+                            areOnlyNotificationsPermissionsRevoked &&
+                                isAppBackupAndRestoreRunning(uid)
                         ) {
                             return@post
                         }
@@ -2541,19 +2713,27 @@
         }
 
         private fun isAppBackupAndRestoreRunning(uid: Int): Boolean {
-            if (checkUidPermission(uid, Manifest.permission.BACKUP, Context.DEVICE_ID_DEFAULT) !=
-                PackageManager.PERMISSION_GRANTED) {
+            if (
+                checkUidPermission(uid, Manifest.permission.BACKUP, Context.DEVICE_ID_DEFAULT) !=
+                    PackageManager.PERMISSION_GRANTED
+            ) {
                 return false
             }
             return try {
                 val contentResolver = context.contentResolver
                 val userId = UserHandle.getUserId(uid)
-                val isInSetup = Settings.Secure.getIntForUser(
-                    contentResolver, Settings.Secure.USER_SETUP_COMPLETE, userId
-                ) == 0
-                val isInDeferredSetup = Settings.Secure.getIntForUser(
-                    contentResolver, Settings.Secure.USER_SETUP_PERSONALIZATION_STATE, userId
-                ) == Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED
+                val isInSetup =
+                    Settings.Secure.getIntForUser(
+                        contentResolver,
+                        Settings.Secure.USER_SETUP_COMPLETE,
+                        userId
+                    ) == 0
+                val isInDeferredSetup =
+                    Settings.Secure.getIntForUser(
+                        contentResolver,
+                        Settings.Secure.USER_SETUP_PERSONALIZATION_STATE,
+                        userId
+                    ) == Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED
                 isInSetup || isInDeferredSetup
             } catch (e: Settings.SettingNotFoundException) {
                 Slog.w(LOG_TAG, "Failed to check if the user is in restore: $e")
@@ -2614,31 +2794,34 @@
         @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
         private val BACKGROUND_RATIONALE_CHANGE_ID = 147316723L
 
-        private val FULLER_PERMISSIONS = ArrayMap<String, String>().apply {
-            this[Manifest.permission.ACCESS_COARSE_LOCATION] =
-                Manifest.permission.ACCESS_FINE_LOCATION
-            this[Manifest.permission.INTERACT_ACROSS_USERS] =
-                Manifest.permission.INTERACT_ACROSS_USERS_FULL
-        }
+        private val FULLER_PERMISSIONS =
+            ArrayMap<String, String>().apply {
+                this[Manifest.permission.ACCESS_COARSE_LOCATION] =
+                    Manifest.permission.ACCESS_FINE_LOCATION
+                this[Manifest.permission.INTERACT_ACROSS_USERS] =
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL
+            }
 
-        private val NOTIFICATIONS_PERMISSIONS = arraySetOf(
-            Manifest.permission.POST_NOTIFICATIONS
-        )
+        private val NOTIFICATIONS_PERMISSIONS = arraySetOf(Manifest.permission.POST_NOTIFICATIONS)
 
-        private const val REVIEW_REQUIRED_FLAGS = PermissionFlags.LEGACY_GRANTED or
-            PermissionFlags.IMPLICIT
-        private const val UNREQUESTABLE_MASK = PermissionFlags.RESTRICTION_REVOKED or
-            PermissionFlags.SYSTEM_FIXED or PermissionFlags.POLICY_FIXED or
-            PermissionFlags.USER_FIXED
+        private const val REVIEW_REQUIRED_FLAGS =
+            PermissionFlags.LEGACY_GRANTED or PermissionFlags.IMPLICIT
+        private const val UNREQUESTABLE_MASK =
+            PermissionFlags.RESTRICTION_REVOKED or
+                PermissionFlags.SYSTEM_FIXED or
+                PermissionFlags.POLICY_FIXED or
+                PermissionFlags.USER_FIXED
 
         private val BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60)
 
-        /** Cap the size of permission trees that 3rd party apps can define; in characters of text  */
+        /**
+         * Cap the size of permission trees that 3rd party apps can define; in characters of text
+         */
         private const val MAX_PERMISSION_TREE_FOOTPRINT = 32768
 
         private const val PERMISSION_ALLOWLIST_MASK =
             PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE or
-            PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM or
-            PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
+                PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM or
+                PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
     }
 }
diff --git a/services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt b/services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt
index bd82935..6b20ef1 100644
--- a/services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt
@@ -25,9 +25,7 @@
 import java.io.FileOutputStream
 import java.io.IOException
 
-/**
- * Read from an [AtomicFile], fallback to reserve file to read the data.
- */
+/** Read from an [AtomicFile], fallback to reserve file to read the data. */
 @Throws(Exception::class)
 inline fun AtomicFile.readWithReserveCopy(block: (FileInputStream) -> Unit) {
     try {
@@ -46,9 +44,7 @@
     }
 }
 
-/**
- * Write to actual file and reserve file.
- */
+/** Write to actual file and reserve file. */
 @Throws(IOException::class)
 inline fun AtomicFile.writeWithReserveCopy(block: (FileOutputStream) -> Unit) {
     val reserveFile = File(baseFile.parentFile, baseFile.name + ".reservecopy")
@@ -66,9 +62,7 @@
     }
 }
 
-/**
- * Write to an [AtomicFile] and close everything safely when done.
- */
+/** Write to an [AtomicFile] and close everything safely when done. */
 @Throws(IOException::class)
 // Renamed to writeInlined() to avoid conflict with the hidden AtomicFile.write() that isn't inline.
 inline fun AtomicFile.writeInlined(block: (FileOutputStream) -> Unit) {
diff --git a/services/permission/java/com/android/server/permission/access/util/BinaryXmlPullParserExtensions.kt b/services/permission/java/com/android/server/permission/access/util/BinaryXmlPullParserExtensions.kt
index 1d27aef..6ab73c7 100644
--- a/services/permission/java/com/android/server/permission/access/util/BinaryXmlPullParserExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/util/BinaryXmlPullParserExtensions.kt
@@ -22,9 +22,7 @@
 import org.xmlpull.v1.XmlPullParser
 import org.xmlpull.v1.XmlPullParserException
 
-/**
- * Parse content from [InputStream] with [BinaryXmlPullParser].
- */
+/** Parse content from [InputStream] with [BinaryXmlPullParser]. */
 @Throws(IOException::class, XmlPullParserException::class)
 inline fun InputStream.parseBinaryXml(block: BinaryXmlPullParser.() -> Unit) {
     BinaryXmlPullParser().apply {
@@ -35,6 +33,7 @@
 
 /**
  * Iterate through child tags of the current tag.
+ *
  * <p>
  * Attributes for the current tag needs to be accessed before this method is called because this
  * method will advance the parser past the start tag of the current tag. The code inspecting each
@@ -50,7 +49,8 @@
 inline fun BinaryXmlPullParser.forEachTag(block: BinaryXmlPullParser.() -> Unit) {
     when (val eventType = eventType) {
         // Document start or start tag of the parent tag.
-        XmlPullParser.START_DOCUMENT, XmlPullParser.START_TAG -> nextTagOrEnd()
+        XmlPullParser.START_DOCUMENT,
+        XmlPullParser.START_TAG -> nextTagOrEnd()
         else -> throw XmlPullParserException("Unexpected event type $eventType")
     }
     while (true) {
@@ -90,7 +90,8 @@
                 nextTagOrEnd()
             }
             // End tag of the parent tag, or document end.
-            XmlPullParser.END_TAG, XmlPullParser.END_DOCUMENT -> break
+            XmlPullParser.END_TAG,
+            XmlPullParser.END_DOCUMENT -> break
             else -> throw XmlPullParserException("Unexpected event type $eventType")
         }
     }
@@ -107,193 +108,146 @@
 inline fun BinaryXmlPullParser.nextTagOrEnd(): Int {
     while (true) {
         when (val eventType = next()) {
-            XmlPullParser.START_TAG, XmlPullParser.END_TAG, XmlPullParser.END_DOCUMENT ->
-                return eventType
+            XmlPullParser.START_TAG,
+            XmlPullParser.END_TAG,
+            XmlPullParser.END_DOCUMENT -> return eventType
             else -> continue
         }
     }
 }
 
-/**
- * @see BinaryXmlPullParser.getName
- */
+/** @see BinaryXmlPullParser.getName */
 inline val BinaryXmlPullParser.tagName: String
     get() = name
 
-/**
- * Check whether an attribute exists for the current tag.
- */
+/** Check whether an attribute exists for the current tag. */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.hasAttribute(name: String): Boolean = getAttributeIndex(name) != -1
 
-/**
- * @see BinaryXmlPullParser.getAttributeIndex
- */
+/** @see BinaryXmlPullParser.getAttributeIndex */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeIndex(name: String): Int = getAttributeIndex(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeIndexOrThrow
- */
+/** @see BinaryXmlPullParser.getAttributeIndexOrThrow */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeIndexOrThrow(name: String): Int =
     getAttributeIndexOrThrow(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeValue
- */
+/** @see BinaryXmlPullParser.getAttributeValue */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeValue(name: String): String? =
     getAttributeValue(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeValue
- */
+/** @see BinaryXmlPullParser.getAttributeValue */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeValueOrThrow(name: String): String =
     getAttributeValue(getAttributeIndexOrThrow(name))
 
-/**
- * @see BinaryXmlPullParser.getAttributeBytesHex
- */
+/** @see BinaryXmlPullParser.getAttributeBytesHex */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeBytesHex(name: String): ByteArray? =
     getAttributeBytesHex(null, name, null)
 
-/**
- * @see BinaryXmlPullParser.getAttributeBytesHex
- */
+/** @see BinaryXmlPullParser.getAttributeBytesHex */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeBytesHexOrThrow(name: String): ByteArray =
     getAttributeBytesHex(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeBytesBase64
- */
+/** @see BinaryXmlPullParser.getAttributeBytesBase64 */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeBytesBase64(name: String): ByteArray? =
     getAttributeBytesBase64(null, name, null)
 
-/**
- * @see BinaryXmlPullParser.getAttributeBytesBase64
- */
+/** @see BinaryXmlPullParser.getAttributeBytesBase64 */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeBytesBase64OrThrow(name: String): ByteArray =
     getAttributeBytesBase64(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeInt
- */
+/** @see BinaryXmlPullParser.getAttributeInt */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeIntOrDefault(name: String, defaultValue: Int): Int =
     getAttributeInt(null, name, defaultValue)
 
-/**
- * @see BinaryXmlPullParser.getAttributeInt
- */
+/** @see BinaryXmlPullParser.getAttributeInt */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeIntOrThrow(name: String): Int =
     getAttributeInt(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeIntHex
- */
+/** @see BinaryXmlPullParser.getAttributeIntHex */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeIntHexOrDefault(name: String, defaultValue: Int): Int =
     getAttributeIntHex(null, name, defaultValue)
 
-/**
- * @see BinaryXmlPullParser.getAttributeIntHex
- */
+/** @see BinaryXmlPullParser.getAttributeIntHex */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeIntHexOrThrow(name: String): Int =
     getAttributeIntHex(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeLong
- */
+/** @see BinaryXmlPullParser.getAttributeLong */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeLongOrDefault(name: String, defaultValue: Long): Long =
     getAttributeLong(null, name, defaultValue)
 
-/**
- * @see BinaryXmlPullParser.getAttributeLong
- */
+/** @see BinaryXmlPullParser.getAttributeLong */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeLongOrThrow(name: String): Long =
     getAttributeLong(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeLongHex
- */
+/** @see BinaryXmlPullParser.getAttributeLongHex */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeLongHexOrDefault(
     name: String,
     defaultValue: Long
 ): Long = getAttributeLongHex(null, name, defaultValue)
 
-/**
- * @see BinaryXmlPullParser.getAttributeLongHex
- */
+/** @see BinaryXmlPullParser.getAttributeLongHex */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeLongHexOrThrow(name: String): Long =
     getAttributeLongHex(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeFloat
- */
+/** @see BinaryXmlPullParser.getAttributeFloat */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeFloatOrDefault(
     name: String,
     defaultValue: Float
 ): Float = getAttributeFloat(null, name, defaultValue)
 
-/**
- * @see BinaryXmlPullParser.getAttributeFloat
- */
+/** @see BinaryXmlPullParser.getAttributeFloat */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeFloatOrThrow(name: String): Float =
     getAttributeFloat(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeDouble
- */
+/** @see BinaryXmlPullParser.getAttributeDouble */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeDoubleOrDefault(
     name: String,
     defaultValue: Double
 ): Double = getAttributeDouble(null, name, defaultValue)
 
-/**
- * @see BinaryXmlPullParser.getAttributeDouble
- */
+/** @see BinaryXmlPullParser.getAttributeDouble */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeDoubleOrThrow(name: String): Double =
     getAttributeDouble(null, name)
 
-/**
- * @see BinaryXmlPullParser.getAttributeBoolean
- */
+/** @see BinaryXmlPullParser.getAttributeBoolean */
 @Suppress("NOTHING_TO_INLINE")
 inline fun BinaryXmlPullParser.getAttributeBooleanOrDefault(
     name: String,
     defaultValue: Boolean
 ): Boolean = getAttributeBoolean(null, name, defaultValue)
 
-/**
- * @see BinaryXmlPullParser.getAttributeBoolean
- */
+/** @see BinaryXmlPullParser.getAttributeBoolean */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(XmlPullParserException::class)
 inline fun BinaryXmlPullParser.getAttributeBooleanOrThrow(name: String): Boolean =
diff --git a/services/permission/java/com/android/server/permission/access/util/BinaryXmlSerializerExtensions.kt b/services/permission/java/com/android/server/permission/access/util/BinaryXmlSerializerExtensions.kt
index c8cd586..6500a7d 100644
--- a/services/permission/java/com/android/server/permission/access/util/BinaryXmlSerializerExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/util/BinaryXmlSerializerExtensions.kt
@@ -20,9 +20,7 @@
 import java.io.IOException
 import java.io.OutputStream
 
-/**
- * Serialize content into [OutputStream] with [BinaryXmlSerializer].
- */
+/** Serialize content into [OutputStream] with [BinaryXmlSerializer]. */
 @Throws(IOException::class)
 inline fun OutputStream.serializeBinaryXml(block: BinaryXmlSerializer.() -> Unit) {
     BinaryXmlSerializer().apply {
@@ -57,54 +55,42 @@
     endTag(null, name)
 }
 
-/**
- * @see BinaryXmlSerializer.attribute
- */
+/** @see BinaryXmlSerializer.attribute */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attribute(name: String, value: String) {
     attribute(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeInterned
- */
+/** @see BinaryXmlSerializer.attributeInterned */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeInterned(name: String, value: String) {
     attributeInterned(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeBytesHex
- */
+/** @see BinaryXmlSerializer.attributeBytesHex */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeBytesHex(name: String, value: ByteArray) {
     attributeBytesHex(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeBytesBase64
- */
+/** @see BinaryXmlSerializer.attributeBytesBase64 */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeBytesBase64(name: String, value: ByteArray) {
     attributeBytesBase64(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeInt
- */
+/** @see BinaryXmlSerializer.attributeInt */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeInt(name: String, value: Int) {
     attributeInt(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeInt
- */
+/** @see BinaryXmlSerializer.attributeInt */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeIntWithDefault(
@@ -117,18 +103,14 @@
     }
 }
 
-/**
- * @see BinaryXmlSerializer.attributeIntHex
- */
+/** @see BinaryXmlSerializer.attributeIntHex */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeIntHex(name: String, value: Int) {
     attributeIntHex(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeIntHex
- */
+/** @see BinaryXmlSerializer.attributeIntHex */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeIntHexWithDefault(
@@ -141,18 +123,14 @@
     }
 }
 
-/**
- * @see BinaryXmlSerializer.attributeLong
- */
+/** @see BinaryXmlSerializer.attributeLong */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeLong(name: String, value: Long) {
     attributeLong(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeLong
- */
+/** @see BinaryXmlSerializer.attributeLong */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeLongWithDefault(
@@ -165,18 +143,14 @@
     }
 }
 
-/**
- * @see BinaryXmlSerializer.attributeLongHex
- */
+/** @see BinaryXmlSerializer.attributeLongHex */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeLongHex(name: String, value: Long) {
     attributeLongHex(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeLongHex
- */
+/** @see BinaryXmlSerializer.attributeLongHex */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeLongHexWithDefault(
@@ -189,18 +163,14 @@
     }
 }
 
-/**
- * @see BinaryXmlSerializer.attributeFloat
- */
+/** @see BinaryXmlSerializer.attributeFloat */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeFloat(name: String, value: Float) {
     attributeFloat(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeFloat
- */
+/** @see BinaryXmlSerializer.attributeFloat */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeFloatWithDefault(
@@ -213,18 +183,14 @@
     }
 }
 
-/**
- * @see BinaryXmlSerializer.attributeDouble
- */
+/** @see BinaryXmlSerializer.attributeDouble */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeDouble(name: String, value: Double) {
     attributeDouble(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeDouble
- */
+/** @see BinaryXmlSerializer.attributeDouble */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeDoubleWithDefault(
@@ -237,18 +203,14 @@
     }
 }
 
-/**
- * @see BinaryXmlSerializer.attributeBoolean
- */
+/** @see BinaryXmlSerializer.attributeBoolean */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeBoolean(name: String, value: Boolean) {
     attributeBoolean(null, name, value)
 }
 
-/**
- * @see BinaryXmlSerializer.attributeBoolean
- */
+/** @see BinaryXmlSerializer.attributeBoolean */
 @Suppress("NOTHING_TO_INLINE")
 @Throws(IOException::class)
 inline fun BinaryXmlSerializer.attributeBooleanWithDefault(
diff --git a/services/permission/java/com/android/server/permission/access/util/PackageVersionMigration.kt b/services/permission/java/com/android/server/permission/access/util/PackageVersionMigration.kt
index a61489c..3ef284b 100644
--- a/services/permission/java/com/android/server/permission/access/util/PackageVersionMigration.kt
+++ b/services/permission/java/com/android/server/permission/access/util/PackageVersionMigration.kt
@@ -22,13 +22,13 @@
 
 object PackageVersionMigration {
     /**
-     * Maps existing permission and app-op version to a unified version during OTA upgrade. The
-     * new unified version is used in determining the upgrade steps for a package (for both
-     * permission and app-ops).
+     * Maps existing permission and app-op version to a unified version during OTA upgrade. The new
+     * unified version is used in determining the upgrade steps for a package (for both permission
+     * and app-ops).
      *
      * @return unified permission/app-op version
      * @throws IllegalStateException if the method is called when there is nothing to migrate i.e.
-     * permission and app-op file does not exist.
+     *   permission and app-op file does not exist.
      */
     internal fun getVersion(userId: Int): Int {
         val permissionMigrationHelper =
diff --git a/services/permission/java/com/android/server/permission/access/util/PermissionApex.kt b/services/permission/java/com/android/server/permission/access/util/PermissionApex.kt
index e6b4e3e..3d835e8 100644
--- a/services/permission/java/com/android/server/permission/access/util/PermissionApex.kt
+++ b/services/permission/java/com/android/server/permission/access/util/PermissionApex.kt
@@ -23,15 +23,11 @@
 object PermissionApex {
     private const val MODULE_NAME = "com.android.permission"
 
-    /**
-     * @see ApexEnvironment.getDeviceProtectedDataDir
-     */
+    /** @see ApexEnvironment.getDeviceProtectedDataDir */
     val systemDataDirectory: File
         get() = apexEnvironment.deviceProtectedDataDir
 
-    /**
-     * @see ApexEnvironment.getDeviceProtectedDataDirForUser
-     */
+    /** @see ApexEnvironment.getDeviceProtectedDataDirForUser */
     fun getUserDataDirectory(userId: Int): File =
         apexEnvironment.getDeviceProtectedDataDirForUser(UserHandle.of(userId))
 
diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp
index 0275c7d..6e4069f 100644
--- a/services/tests/displayservicetests/Android.bp
+++ b/services/tests/displayservicetests/Android.bp
@@ -40,6 +40,7 @@
         "services.core",
         "servicestests-utils",
         "testables",
+        "TestParameterInjector",
     ],
 
     defaults: [
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 2396905..d021f1d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -114,17 +114,18 @@
 import com.android.server.display.DisplayManagerService.DeviceStateListener;
 import com.android.server.display.DisplayManagerService.SyncRoot;
 import com.android.server.display.feature.DisplayManagerFlags;
+import com.android.server.display.notifications.DisplayNotificationManager;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.lights.LightsManager;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.sensors.SensorManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
+import com.google.common.truth.Expect;
+
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
 
-import com.google.common.truth.Expect;
-
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -201,9 +202,12 @@
                 @Override
                 LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
                         Handler handler, DisplayAdapter.Listener displayAdapterListener,
-                        DisplayManagerFlags flags) {
+                        DisplayManagerFlags flags,
+                        DisplayNotificationManager displayNotificationManager) {
                     return new LocalDisplayAdapter(syncRoot, context, handler,
-                            displayAdapterListener, flags, new LocalDisplayAdapter.Injector() {
+                            displayAdapterListener, flags,
+                            mMockedDisplayNotificationManager,
+                            new LocalDisplayAdapter.Injector() {
                         @Override
                         public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() {
                             return mSurfaceControlProxy;
@@ -248,13 +252,15 @@
         @Override
         LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
                 Handler handler, DisplayAdapter.Listener displayAdapterListener,
-                DisplayManagerFlags flags) {
+                DisplayManagerFlags flags,
+                DisplayNotificationManager displayNotificationManager) {
             return new LocalDisplayAdapter(
                     syncRoot,
                     context,
                     handler,
                     displayAdapterListener,
                     flags,
+                    mMockedDisplayNotificationManager,
                     new LocalDisplayAdapter.Injector() {
                         @Override
                         public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() {
@@ -288,6 +294,7 @@
 
     private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
 
+    @Mock DisplayNotificationManager mMockedDisplayNotificationManager;
     @Mock IMediaProjectionManager mMockProjectionService;
     @Mock IVirtualDeviceManager mIVirtualDeviceManager;
     @Mock InputManagerInternal mMockInputManagerInternal;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 147e8f2..9ac0062 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -60,6 +60,7 @@
 import com.android.server.display.LocalDisplayAdapter.BacklightAdapter;
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.mode.DisplayModeDirector;
+import com.android.server.display.notifications.DisplayNotificationManager;
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LogicalLight;
 
@@ -113,6 +114,8 @@
     @Mock
     private LogicalLight mMockedBacklight;
     @Mock
+    private DisplayNotificationManager mMockedDisplayNotificationManager;
+    @Mock
     private DisplayManagerFlags mFlags;
 
     private Handler mHandler;
@@ -148,7 +151,7 @@
         mInjector = new Injector();
         when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
         mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler,
-                mListener, mFlags, mInjector);
+                mListener, mFlags, mMockedDisplayNotificationManager, mInjector);
         spyOn(mAdapter);
         doReturn(mMockedContext).when(mAdapter).getOverlayContext();
 
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/displayservicetests/src/com/android/server/display/notifications/ConnectedDisplayUsbErrorsDetectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/notifications/ConnectedDisplayUsbErrorsDetectorTest.java
new file mode 100644
index 0000000..d5a92cb
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/notifications/ConnectedDisplayUsbErrorsDetectorTest.java
@@ -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.server.display.notifications;
+
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_ENABLED;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE;
+import static android.hardware.usb.DisplayPortAltModeInfo.LINK_TRAINING_STATUS_FAILURE;
+
+import static org.junit.Assume.assumeFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.usb.DisplayPortAltModeInfo;
+import android.hardware.usb.UsbManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.display.feature.DisplayManagerFlags;
+import com.android.server.display.notifications.ConnectedDisplayUsbErrorsDetector.Injector;
+
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link ConnectedDisplayUsbErrorsDetector}
+ * Run: atest ConnectedDisplayUsbErrorsDetectorTest
+ */
+@SmallTest
+@RunWith(TestParameterInjector.class)
+public class ConnectedDisplayUsbErrorsDetectorTest {
+    @Mock
+    private Injector mMockedInjector;
+    @Mock
+    private UsbManager mMockedUsbManager;
+    @Mock
+    private DisplayManagerFlags mMockedFlags;
+    @Mock
+    private ConnectedDisplayUsbErrorsDetector.Listener mMockedListener;
+
+    /** Setup tests. */
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testNoErrorTypes(
+            @TestParameter final boolean isUsbManagerAvailable,
+            @TestParameter final boolean isUsbErrorsNotificationEnabled) {
+        // This is tested in #testErrorOnUsbCableNotCapableDp and #testErrorOnDpLinkTrainingFailure
+        assumeFalse(isUsbManagerAvailable && isUsbErrorsNotificationEnabled);
+        var detector = createErrorsDetector(isUsbManagerAvailable, isUsbErrorsNotificationEnabled);
+        // None of these should trigger an error now.
+        detector.onDisplayPortAltModeInfoChanged("portId", createInfoOnUsbCableNotCapableDp());
+        detector.onDisplayPortAltModeInfoChanged("portId", createInfoOnDpLinkTrainingFailure());
+        verify(mMockedUsbManager, never()).registerDisplayPortAltModeInfoListener(any(), any());
+        verify(mMockedListener, never()).onCableNotCapableDisplayPort();
+        verify(mMockedListener, never()).onDisplayPortLinkTrainingFailure();
+    }
+
+    @Test
+    public void testErrorOnUsbCableNotCapableDp() {
+        var detector = createErrorsDetector(/*isUsbManagerAvailable=*/ true,
+                /*isUsbErrorsNotificationEnabled=*/ true);
+        detector.onDisplayPortAltModeInfoChanged("portId", createInfoOnUsbCableNotCapableDp());
+        verify(mMockedUsbManager).registerDisplayPortAltModeInfoListener(any(), any());
+        verify(mMockedListener).onCableNotCapableDisplayPort();
+        verify(mMockedListener, never()).onDisplayPortLinkTrainingFailure();
+    }
+
+    @Test
+    public void testErrorOnDpLinkTrainingFailure() {
+        var detector = createErrorsDetector(/*isUsbManagerAvailable=*/ true,
+                /*isUsbErrorsNotificationEnabled=*/ true);
+        detector.onDisplayPortAltModeInfoChanged("portId", createInfoOnDpLinkTrainingFailure());
+        verify(mMockedUsbManager).registerDisplayPortAltModeInfoListener(any(), any());
+        verify(mMockedListener, never()).onCableNotCapableDisplayPort();
+        verify(mMockedListener).onDisplayPortLinkTrainingFailure();
+    }
+
+    private ConnectedDisplayUsbErrorsDetector createErrorsDetector(
+            final boolean isUsbManagerAvailable,
+            final boolean isConnectedDisplayUsbErrorsNotificationEnabled) {
+        when(mMockedFlags.isConnectedDisplayErrorHandlingEnabled())
+                .thenReturn(isConnectedDisplayUsbErrorsNotificationEnabled);
+        when(mMockedInjector.getUsbManager()).thenReturn(
+                (isUsbManagerAvailable) ? mMockedUsbManager : null);
+        var detector = new ConnectedDisplayUsbErrorsDetector(mMockedFlags,
+                ApplicationProvider.getApplicationContext(), mMockedInjector);
+        detector.registerListener(mMockedListener);
+        return detector;
+    }
+
+    private DisplayPortAltModeInfo createInfoOnUsbCableNotCapableDp() {
+        return new DisplayPortAltModeInfo(
+                    DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED,
+                    DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE, -1, false, 0);
+    }
+
+    private DisplayPortAltModeInfo createInfoOnDpLinkTrainingFailure() {
+        return new DisplayPortAltModeInfo(
+                    DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED,
+                    DISPLAYPORT_ALT_MODE_STATUS_ENABLED, -1, false,
+                    LINK_TRAINING_STATUS_FAILURE);
+    }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/notifications/DisplayNotificationManagerTest.java b/services/tests/displayservicetests/src/com/android/server/display/notifications/DisplayNotificationManagerTest.java
new file mode 100644
index 0000000..1d2034b
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/notifications/DisplayNotificationManagerTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.notifications;
+
+import static android.app.Notification.FLAG_ONGOING_EVENT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.display.feature.DisplayManagerFlags;
+import com.android.server.display.notifications.DisplayNotificationManager.Injector;
+
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link DisplayNotificationManager}
+ * Run: atest DisplayNotificationManagerTest
+ */
+@SmallTest
+@RunWith(TestParameterInjector.class)
+public class DisplayNotificationManagerTest {
+    @Mock
+    private Injector mMockedInjector;
+    @Mock
+    private NotificationManager mMockedNotificationManager;
+    @Mock
+    private DisplayManagerFlags mMockedFlags;
+    @Captor
+    private ArgumentCaptor<String> mNotifyTagCaptor;
+    @Captor
+    private ArgumentCaptor<Integer> mNotifyNoteIdCaptor;
+    @Captor
+    private ArgumentCaptor<Notification> mNotifyAsUserNotificationCaptor;
+
+    /** Setup tests. */
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testNotificationOnHotplugConnectionError() {
+        var dnm = createDisplayNotificationManager(/*isNotificationManagerAvailable=*/ true,
+                /*isErrorHandlingEnabled=*/ true);
+        dnm.onHotplugConnectionError();
+        assertExpectedNotification();
+    }
+
+    @Test
+    public void testNotificationOnDisplayPortLinkTrainingFailure() {
+        var dnm = createDisplayNotificationManager(/*isNotificationManagerAvailable=*/ true,
+                /*isErrorHandlingEnabled=*/ true);
+        dnm.onDisplayPortLinkTrainingFailure();
+        assertExpectedNotification();
+    }
+
+    @Test
+    public void testNotificationOnCableNotCapableDisplayPort() {
+        var dnm = createDisplayNotificationManager(/*isNotificationManagerAvailable=*/ true,
+                /*isErrorHandlingEnabled=*/ true);
+        dnm.onCableNotCapableDisplayPort();
+        assertExpectedNotification();
+    }
+
+    @Test
+    public void testNoErrorNotification(
+            @TestParameter final boolean isNotificationManagerAvailable,
+            @TestParameter final boolean isErrorHandlingEnabled) {
+        /* This case is tested by #testNotificationOnHotplugConnectionError,
+            #testNotificationOnDisplayPortLinkTrainingFailure,
+            #testNotificationOnCableNotCapableDisplayPort */
+        assumeFalse(isNotificationManagerAvailable && isErrorHandlingEnabled);
+        var dnm = createDisplayNotificationManager(isNotificationManagerAvailable,
+                isErrorHandlingEnabled);
+        // None of these methods should trigger a notification now.
+        dnm.onHotplugConnectionError();
+        dnm.onDisplayPortLinkTrainingFailure();
+        dnm.onCableNotCapableDisplayPort();
+        verify(mMockedNotificationManager, never()).notify(anyString(), anyInt(), any());
+    }
+
+    private DisplayNotificationManager createDisplayNotificationManager(
+            final boolean isNotificationManagerAvailable,
+            final boolean isErrorHandlingEnabled) {
+        when(mMockedFlags.isConnectedDisplayErrorHandlingEnabled()).thenReturn(
+                isErrorHandlingEnabled);
+        when(mMockedInjector.getNotificationManager()).thenReturn(
+                (isNotificationManagerAvailable) ? mMockedNotificationManager : null);
+        // Usb errors detector is tested in ConnectedDisplayUsbErrorsDetectorTest
+        when(mMockedInjector.getUsbErrorsDetector()).thenReturn(/* usbErrorsDetector= */ null);
+        final var displayNotificationManager = new DisplayNotificationManager(mMockedFlags,
+                ApplicationProvider.getApplicationContext(), mMockedInjector);
+        displayNotificationManager.onBootCompleted();
+        return displayNotificationManager;
+    }
+
+    private void assertExpectedNotification() {
+        verify(mMockedNotificationManager).notify(
+                mNotifyTagCaptor.capture(),
+                mNotifyNoteIdCaptor.capture(),
+                mNotifyAsUserNotificationCaptor.capture());
+        assertThat(mNotifyTagCaptor.getValue()).isEqualTo("DisplayNotificationManager");
+        assertThat((int) mNotifyNoteIdCaptor.getValue()).isEqualTo(1);
+        final var notification = mNotifyAsUserNotificationCaptor.getValue();
+        assertThat(notification.getChannelId()).isEqualTo("ALERTS");
+        assertThat(notification.category).isEqualTo(Notification.CATEGORY_ERROR);
+        assertThat(notification.visibility).isEqualTo(Notification.VISIBILITY_PUBLIC);
+        assertThat(notification.flags & FLAG_ONGOING_EVENT).isEqualTo(0);
+        assertThat(notification.when).isEqualTo(0);
+        assertThat(notification.getTimeoutAfter()).isEqualTo(30000L);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
index 7cc01e1..4329b6f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
@@ -160,6 +160,8 @@
         mPrefetchController = new PrefetchController(mJobSchedulerService);
         mPcConstants = mPrefetchController.getPcConstants();
 
+        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
+
         setUidBias(Process.myUid(), JobInfo.BIAS_DEFAULT);
 
         verify(mUsageStatsManagerInternal)
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/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
index 70527ce..44d6760 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
@@ -238,7 +238,7 @@
         }
 
         @Override
-        Handler getHandler(Handler.Callback callback) {
+        Handler newHandler(Handler.Callback callback) {
             if (mTestHandler == null) {
                 mTestHandler = new TestHandler(mHandler.getLooper(), callback, mImmediate);
             }
@@ -250,14 +250,18 @@
             return mTestHandler;
         }
 
+        /**
+         * This override returns the tracker supplied in the constructor.  It does not create a
+         * new one.
+         */
         @Override
-        AnrTimer.CpuTracker getTracker() {
+        AnrTimer.CpuTracker newTracker() {
             return mTracker;
         }
 
         /** For test purposes, always enable the feature. */
         @Override
-        boolean getFeatureEnabled() {
+        boolean isFeatureEnabled() {
             return true;
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 0230d77..e3e708e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -47,6 +47,7 @@
 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.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
@@ -64,6 +65,7 @@
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.biometrics.IBiometricPromptStatusListener;
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -1751,6 +1753,45 @@
         verifyNoMoreInteractions(callback);
     }
 
+    @Test
+    public void testRegisterBiometricPromptOnKeyguardCallback_authenticationAlreadyStarted()
+            throws Exception {
+        final IBiometricPromptStatusListener callback =
+                mock(IBiometricPromptStatusListener.class);
+
+        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                true /* requireConfirmation */, null /* authenticators */);
+        mBiometricService.mImpl.registerBiometricPromptStatusListener(callback);
+
+        verify(callback).onBiometricPromptShowing();
+    }
+
+    @Test
+    public void testRegisterBiometricPromptOnKeyguardCallback_startAuth_dismissDialog()
+            throws Exception {
+        final IBiometricPromptStatusListener listener =
+                mock(IBiometricPromptStatusListener.class);
+        setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
+        mBiometricService.mImpl.registerBiometricPromptStatusListener(listener);
+        waitForIdle();
+
+        verify(listener).onBiometricPromptIdle();
+
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                true /* requireConfirmation */, null /* authenticators */);
+        waitForIdle();
+
+        verify(listener).onBiometricPromptShowing();
+
+        final byte[] hat = generateRandomHAT();
+        mBiometricService.mAuthSession.mSysuiReceiver.onDialogDismissed(
+                BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED, hat);
+        waitForIdle();
+
+        verify(listener, times(2)).onBiometricPromptIdle();
+    }
+
     // Helper methods
 
     private int invokeCanAuthenticate(BiometricService service, int authenticators)
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/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
index e7777f7..67b70684 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -436,6 +436,24 @@
         verify(mMockRemoteContentProtectionService).onLoginDetected(PARCELED_EVENTS);
     }
 
+    @Test
+    public void parseContentProtectionGroupsConfig_null() {
+        ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
+        assertThat(service.parseContentProtectionGroupsConfig(null)).isEmpty();
+    }
+
+    @Test
+    public void parseContentProtectionGroupsConfig_empty() {
+        ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
+        assertThat(service.parseContentProtectionGroupsConfig("")).isEmpty();
+    }
+
+    @Test
+    public void parseContentProtectionGroupsConfig_notEmpty() {
+        ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
+        assertThat(service.parseContentProtectionGroupsConfig("a")).isEmpty();
+    }
+
     private class TestContentCaptureManagerService extends ContentCaptureManagerService {
 
         TestContentCaptureManagerService() {
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/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index d1f4961..8891413 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -43,6 +43,8 @@
         // 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/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index c05f814..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) {
-        detailedAssertEquals(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 91129a1..3d4b4a6 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -687,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);
diff --git a/services/tests/vibrator/Android.bp b/services/tests/vibrator/Android.bp
index ca5cfa5..9544106 100644
--- a/services/tests/vibrator/Android.bp
+++ b/services/tests/vibrator/Android.bp
@@ -27,6 +27,7 @@
         "androidx.test.runner",
         "androidx.test.rules",
         "androidx.test.ext.junit",
+        "flag-junit",
         "frameworks-base-testutils",
         "frameworks-services-vibrator-testutils",
         "junit",
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackCustomizationTest.java b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackCustomizationTest.java
index bc826a3..04158c4 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackCustomizationTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackCustomizationTest.java
@@ -31,6 +31,8 @@
 import android.content.res.Resources;
 import android.os.VibrationEffect;
 import android.os.VibratorInfo;
+import android.os.vibrator.Flags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.AtomicFile;
 import android.util.SparseArray;
 
@@ -49,6 +51,8 @@
 import java.io.FileOutputStream;
 
 public class HapticFeedbackCustomizationTest {
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Rule public MockitoRule rule = MockitoJUnit.rule();
 
     // Pairs of valid vibration XML along with their equivalent VibrationEffect.
@@ -77,6 +81,7 @@
     @Before
     public void setUp() {
         when(mVibratorInfoMock.areVibrationFeaturesSupported(any())).thenReturn(true);
+        mSetFlagsRule.enableFlags(Flags.FLAG_HAPTIC_FEEDBACK_VIBRATION_OEM_CUSTOMIZATION_ENABLED);
     }
 
     @Test
@@ -87,6 +92,21 @@
     }
 
     @Test
+    public void testParseCustomizations_featureFlagDisabled_returnsNull() throws Exception {
+        mSetFlagsRule.disableFlags(Flags.FLAG_HAPTIC_FEEDBACK_VIBRATION_OEM_CUSTOMIZATION_ENABLED);
+        // Valid customization XML.
+        String xml = "<haptic-feedback-constants>"
+                + "<constant id=\"10\">"
+                + COMPOSITION_VIBRATION_XML
+                + "</constant>"
+                + "</haptic-feedback-constants>";
+        setupCustomizationFile(xml);
+
+        assertThat(HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorInfoMock))
+                .isNull();
+    }
+
+    @Test
     public void testParseCustomizations_oneVibrationCustomization_success() throws Exception {
         String xml = "<haptic-feedback-constants>"
                 + "<constant id=\"10\">"
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/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index 6c48a69..9f43a17 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -94,6 +94,16 @@
     }
 
     @Test
+    public void test_selectiveCloneLunchRemoteTransition() {
+        final RemoteTransition transition = mock(RemoteTransition.class);
+        final SafeActivityOptions clone = new SafeActivityOptions(
+                ActivityOptions.makeRemoteTransition(transition))
+                .selectiveCloneLaunchOptions();
+
+        assertSame(clone.getOriginalOptions().getRemoteTransition(), transition);
+    }
+
+    @Test
     public void test_getOptions() {
         // Mock everything necessary
         MockitoSession mockingSession = mockitoSession()
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 474720f..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;
 
@@ -2433,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/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 98bbb40..7a0bf90 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5073,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";
@@ -5648,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
@@ -5661,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";
@@ -5674,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";
@@ -5687,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";
@@ -5712,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";
@@ -5732,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";
@@ -5742,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";
@@ -5757,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";
@@ -9640,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.
      *
@@ -10526,6 +10523,8 @@
         auto_data_switch_rat_signal_score_string_bundle.putIntArray(
                 "LTE", new int[]{3731, 5965, 8618, 11179, 13384});
         auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+                "LTE_CA", new int[]{3831, 6065, 8718, 11379, 13484});
+        auto_data_switch_rat_signal_score_string_bundle.putIntArray(
                 "NR_SA", new int[]{5288, 6795, 6955, 7562, 9713});
         auto_data_switch_rat_signal_score_string_bundle.putIntArray(
                 "NR_NSA", new int[]{5463, 6827, 8029, 9007, 9428});
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/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/Input/Android.bp b/tests/Input/Android.bp
index f910b8b..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",
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/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
index 56ab755..7e43566 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
@@ -37,6 +37,8 @@
     private var window: Window? = null
     private var currentModeDisplay: TextView? = null
 
+    private var desiredRatio = 0.0f
+
     override fun onFinishInflate() {
         super.onFinishInflate()
         val window = window ?: throw IllegalStateException("Failed to attach window")
@@ -67,6 +69,7 @@
 
     override fun onAttachedToWindow() {
         super.onAttachedToWindow()
+        desiredRatio = window?.desiredHdrHeadroom ?: 0.0f
         val hdrVis = if (display.isHdrSdrRatioAvailable) {
             display.registerHdrSdrRatioChangedListener({ it.run() }, hdrSdrListener)
             View.VISIBLE
@@ -83,6 +86,11 @@
     }
 
     private fun setColorMode(newMode: Int) {
+        if (newMode == ActivityInfo.COLOR_MODE_HDR &&
+                window!!.colorMode == ActivityInfo.COLOR_MODE_HDR) {
+            desiredRatio = (desiredRatio + 1) % 5.0f
+            window!!.desiredHdrHeadroom = desiredRatio
+        }
         window!!.colorMode = newMode
         updateModeInfoDisplay()
     }
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-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